In [1]:
######## snakemake preamble start (automatically inserted, do not edit) ########
import sys; sys.path.extend(['/home/ckikawa/.conda/envs/seqneut-pipeline/lib/python3.11/site-packages', '/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/seqneut-pipeline', '/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024', '/home/ckikawa/.conda/envs/seqneut-pipeline/bin', '/home/ckikawa/.conda/envs/seqneut-pipeline/lib/python3.11', '/home/ckikawa/.conda/envs/seqneut-pipeline/lib/python3.11/lib-dynload', '/home/ckikawa/.local/lib/python3.11/site-packages', '/home/ckikawa/.conda/envs/seqneut-pipeline/lib/python3.11/site-packages', '/home/ckikawa/.cache/snakemake/snakemake/source-cache/runtime-cache/tmpy6xj203u/file/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/seqneut-pipeline/notebooks', '/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/seqneut-pipeline/notebooks']); import pickle; snakemake = pickle.loads(b'\x80\x04\x95\x9b\x83\x00\x00\x00\x00\x00\x00\x8c\x10snakemake.script\x94\x8c\tSnakemake\x94\x93\x94)\x81\x94}\x94(\x8c\x05input\x94\x8c\x0csnakemake.io\x94\x8c\nInputFiles\x94\x93\x94)\x81\x94(\x8c7results/barcode_counts/plate7_A230212d0_rd512_100.0.csv\x94\x8c7results/barcode_counts/plate7_A230212d0_rd512_150.0.csv\x94\x8c7results/barcode_counts/plate7_A230212d0_rd512_225.0.csv\x94\x8c7results/barcode_counts/plate7_A230212d0_rd512_337.5.csv\x94\x8c8results/barcode_counts/plate7_A230212d0_rd512_506.25.csv\x94\x8c9results/barcode_counts/plate7_A230212d0_rd512_759.375.csv\x94\x8c;results/barcode_counts/plate7_A230212d0_rd512_1139.0625.csv\x94\x8c<results/barcode_counts/plate7_A230212d0_rd512_1708.59375.csv\x94\x8c=results/barcode_counts/plate7_A230212d0_rd512_2562.890625.csv\x94\x8c=results/barcode_counts/plate7_A230212d0_rd512_3844.335938.csv\x94\x8c=results/barcode_counts/plate7_A230212d0_rd512_5766.503906.csv\x94\x8c(results/barcode_counts/plate7_none-1.csv\x94\x8c8results/barcode_counts/plate7_A230212d28_rd512_100.0.csv\x94\x8c8results/barcode_counts/plate7_A230212d28_rd512_150.0.csv\x94\x8c8results/barcode_counts/plate7_A230212d28_rd512_225.0.csv\x94\x8c8results/barcode_counts/plate7_A230212d28_rd512_337.5.csv\x94\x8c9results/barcode_counts/plate7_A230212d28_rd512_506.25.csv\x94\x8c:results/barcode_counts/plate7_A230212d28_rd512_759.375.csv\x94\x8c<results/barcode_counts/plate7_A230212d28_rd512_1139.0625.csv\x94\x8c=results/barcode_counts/plate7_A230212d28_rd512_1708.59375.csv\x94\x8c>results/barcode_counts/plate7_A230212d28_rd512_2562.890625.csv\x94\x8c>results/barcode_counts/plate7_A230212d28_rd512_3844.335938.csv\x94\x8c>results/barcode_counts/plate7_A230212d28_rd512_5766.503906.csv\x94\x8c(results/barcode_counts/plate7_none-2.csv\x94\x8c6results/barcode_fates/plate7_A230212d0_rd512_100.0.csv\x94\x8c6results/barcode_fates/plate7_A230212d0_rd512_150.0.csv\x94\x8c6results/barcode_fates/plate7_A230212d0_rd512_225.0.csv\x94\x8c6results/barcode_fates/plate7_A230212d0_rd512_337.5.csv\x94\x8c7results/barcode_fates/plate7_A230212d0_rd512_506.25.csv\x94\x8c8results/barcode_fates/plate7_A230212d0_rd512_759.375.csv\x94\x8c:results/barcode_fates/plate7_A230212d0_rd512_1139.0625.csv\x94\x8c;results/barcode_fates/plate7_A230212d0_rd512_1708.59375.csv\x94\x8c<results/barcode_fates/plate7_A230212d0_rd512_2562.890625.csv\x94\x8c<results/barcode_fates/plate7_A230212d0_rd512_3844.335938.csv\x94\x8c<results/barcode_fates/plate7_A230212d0_rd512_5766.503906.csv\x94\x8c\'results/barcode_fates/plate7_none-1.csv\x94\x8c7results/barcode_fates/plate7_A230212d28_rd512_100.0.csv\x94\x8c7results/barcode_fates/plate7_A230212d28_rd512_150.0.csv\x94\x8c7results/barcode_fates/plate7_A230212d28_rd512_225.0.csv\x94\x8c7results/barcode_fates/plate7_A230212d28_rd512_337.5.csv\x94\x8c8results/barcode_fates/plate7_A230212d28_rd512_506.25.csv\x94\x8c9results/barcode_fates/plate7_A230212d28_rd512_759.375.csv\x94\x8c;results/barcode_fates/plate7_A230212d28_rd512_1139.0625.csv\x94\x8c<results/barcode_fates/plate7_A230212d28_rd512_1708.59375.csv\x94\x8c=results/barcode_fates/plate7_A230212d28_rd512_2562.890625.csv\x94\x8c=results/barcode_fates/plate7_A230212d28_rd512_3844.335938.csv\x94\x8c=results/barcode_fates/plate7_A230212d28_rd512_5766.503906.csv\x94\x8c\'results/barcode_fates/plate7_none-2.csv\x94\x8c)data/viral_libraries/2023_H3N2_Kikawa.csv\x94\x8c3data/neut_standard_sets/loes2023_neut_standards.csv\x94e}\x94(\x8c\x06_names\x94}\x94(\x8c\ncount_csvs\x94K\x00K\x18\x86\x94\x8c\tfate_csvs\x94K\x18K0\x86\x94\x8c\x11viral_library_csv\x94K0N\x86\x94\x8c\x15neut_standard_set_csv\x94K1N\x86\x94u\x8c\x12_allowed_overrides\x94]\x94(\x8c\x05index\x94\x8c\x04sort\x94ehI\x8c\tfunctools\x94\x8c\x07partial\x94\x93\x94h\x06\x8c\x19Namedlist._used_attribute\x94\x93\x94\x85\x94R\x94(hO)}\x94\x8c\x05_name\x94hIsNt\x94bhJhMhO\x85\x94R\x94(hO)}\x94hShJsNt\x94bh?h\x06\x8c\tNamedlist\x94\x93\x94)\x81\x94(h\nh\x0bh\x0ch\rh\x0eh\x0fh\x10h\x11h\x12h\x13h\x14h\x15h\x16h\x17h\x18h\x19h\x1ah\x1bh\x1ch\x1dh\x1eh\x1fh h!e}\x94(h=}\x94hG]\x94(hIhJehIhMhO\x85\x94R\x94(hO)}\x94hShIsNt\x94bhJhMhO\x85\x94R\x94(hO)}\x94hShJsNt\x94bubhAhZ)\x81\x94(h"h#h$h%h&h\'h(h)h*h+h,h-h.h/h0h1h2h3h4h5h6h7h8h9e}\x94(h=}\x94hG]\x94(hIhJehIhMhO\x85\x94R\x94(hO)}\x94hShIsNt\x94bhJhMhO\x85\x94R\x94(hO)}\x94hShJsNt\x94bubhCh:hEh;ub\x8c\x06output\x94h\x06\x8c\x0bOutputFiles\x94\x93\x94)\x81\x94(\x8c"results/plates/plate7/qc_drops.yml\x94\x8c*results/plates/plate7/frac_infectivity.csv\x94\x8c#results/plates/plate7/curvefits.csv\x94\x8c&results/plates/plate7/curvefits.pickle\x94e}\x94(h=}\x94(\x8c\x08qc_drops\x94K\x00N\x86\x94\x8c\x14frac_infectivity_csv\x94K\x01N\x86\x94\x8c\x08fits_csv\x94K\x02N\x86\x94\x8c\x0bfits_pickle\x94K\x03N\x86\x94uhG]\x94(hIhJehIhMhO\x85\x94R\x94(hO)}\x94hShIsNt\x94bhJhMhO\x85\x94R\x94(hO)}\x94hShJsNt\x94bh}hwh\x7fhxh\x81hyh\x83hzub\x8c\x06params\x94h\x06\x8c\x06Params\x94\x93\x94)\x81\x94(]\x94(\x8c\x1cplate7_A230212d0_rd512_100.0\x94\x8c\x1cplate7_A230212d0_rd512_150.0\x94\x8c\x1cplate7_A230212d0_rd512_225.0\x94\x8c\x1cplate7_A230212d0_rd512_337.5\x94\x8c\x1dplate7_A230212d0_rd512_506.25\x94\x8c\x1eplate7_A230212d0_rd512_759.375\x94\x8c plate7_A230212d0_rd512_1139.0625\x94\x8c!plate7_A230212d0_rd512_1708.59375\x94\x8c"plate7_A230212d0_rd512_2562.890625\x94\x8c"plate7_A230212d0_rd512_3844.335938\x94\x8c"plate7_A230212d0_rd512_5766.503906\x94\x8c\rplate7_none-1\x94\x8c\x1dplate7_A230212d28_rd512_100.0\x94\x8c\x1dplate7_A230212d28_rd512_150.0\x94\x8c\x1dplate7_A230212d28_rd512_225.0\x94\x8c\x1dplate7_A230212d28_rd512_337.5\x94\x8c\x1eplate7_A230212d28_rd512_506.25\x94\x8c\x1fplate7_A230212d28_rd512_759.375\x94\x8c!plate7_A230212d28_rd512_1139.0625\x94\x8c"plate7_A230212d28_rd512_1708.59375\x94\x8c#plate7_A230212d28_rd512_2562.890625\x94\x8c#plate7_A230212d28_rd512_3844.335938\x94\x8c#plate7_A230212d28_rd512_5766.503906\x94\x8c\rplate7_none-2\x94e}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94\x8c\n2024-02-07\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-02-07_plate_mapping_file6.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(\x8c\x1bavg_barcode_counts_per_well\x94M\xf4\x01\x8c\x1fmin_neut_standard_frac_per_well\x94G?tz\xe1G\xae\x14{\x8c"no_serum_per_viral_barcode_filters\x94}\x94(\x8c\x08min_frac\x94G?\x1a6\xe2\xeb\x1cC-\x8c\x0fmax_fold_change\x94K\x04\x8c\tmax_wells\x94K\x02u\x8c!per_neut_standard_barcode_filters\x94}\x94(\x8c\x08min_frac\x94G?tz\xe1G\xae\x14{\x8c\x0fmax_fold_change\x94K\x04\x8c\tmax_wells\x94K\x02u\x8c min_neut_standard_count_per_well\x94M\xe8\x03\x8c)min_no_serum_count_per_viral_barcode_well\x94Kd\x8c+max_frac_infectivity_per_viral_barcode_well\x94K\x03\x8c)min_dilutions_per_barcode_serum_replicate\x94K\x06u\x8c\x0fcurvefit_params\x94}\x94(\x8c\x18frac_infectivity_ceiling\x94K\x01\x8c\x06fixtop\x94]\x94(G?\xe3333333K\x01e\x8c\tfixbottom\x94K\x00\x8c\x08fixslope\x94]\x94(G?\xe9\x99\x99\x99\x99\x99\x9aK\neu\x8c\x0bcurvefit_qc\x94}\x94(\x8c\x1dmax_frac_infectivity_at_least\x94G\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x0fgoodness_of_fit\x94}\x94(\x8c\x06min_R2\x94G?\xe0\x00\x00\x00\x00\x00\x00\x8c\x08max_RMSD\x94G?\xc3333333u\x8c#serum_replicates_ignore_curvefit_qc\x94]\x94\x8c+barcode_serum_replicates_ignore_curvefit_qc\x94]\x94u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\x08upstream\x94\x8c\x1cCCTACAATGTCGGATTTGTATTTAATAG\x94\x8c\ndownstream\x94\x8c\x00\x94\x8c\x04minq\x94K\x14\x8c\x11upstream_mismatch\x94K\x04\x8c\x0ebc_orientation\x94\x8c\x02R2\x94u\x8c\x07samples\x94}\x94(\x8c\x04well\x94}\x94(K\x00\x8c\x02D1\x94K\x01\x8c\x02D2\x94K\x02\x8c\x02D3\x94K\x03\x8c\x02D4\x94K\x04\x8c\x02D5\x94K\x05\x8c\x02D6\x94K\x06\x8c\x02D7\x94K\x07\x8c\x02D8\x94K\x08\x8c\x02D9\x94K\t\x8c\x03D10\x94K\n\x8c\x03D11\x94K\x0b\x8c\x03D12\x94K\x0c\x8c\x02H1\x94K\r\x8c\x02H2\x94K\x0e\x8c\x02H3\x94K\x0f\x8c\x02H4\x94K\x10\x8c\x02H5\x94K\x11\x8c\x02H6\x94K\x12\x8c\x02H7\x94K\x13\x8c\x02H8\x94K\x14\x8c\x02H9\x94K\x15\x8c\x03H10\x94K\x16\x8c\x03H11\x94K\x17\x8c\x03H12\x94u\x8c\x05serum\x94}\x94(K\x00\x8c\x0fA230212d0_rd512\x94K\x01j\x05\x01\x00\x00K\x02j\x05\x01\x00\x00K\x03j\x05\x01\x00\x00K\x04j\x05\x01\x00\x00K\x05j\x05\x01\x00\x00K\x06j\x05\x01\x00\x00K\x07j\x05\x01\x00\x00K\x08j\x05\x01\x00\x00K\tj\x05\x01\x00\x00K\nj\x05\x01\x00\x00K\x0b\x8c\x04none\x94K\x0c\x8c\x10A230212d28_rd512\x94K\rj\x07\x01\x00\x00K\x0ej\x07\x01\x00\x00K\x0fj\x07\x01\x00\x00K\x10j\x07\x01\x00\x00K\x11j\x07\x01\x00\x00K\x12j\x07\x01\x00\x00K\x13j\x07\x01\x00\x00K\x14j\x07\x01\x00\x00K\x15j\x07\x01\x00\x00K\x16j\x07\x01\x00\x00K\x17j\x06\x01\x00\x00u\x8c\x0fdilution_factor\x94}\x94(K\x00G@Y\x00\x00\x00\x00\x00\x00K\x01G@b\xc0\x00\x00\x00\x00\x00K\x02G@l \x00\x00\x00\x00\x00K\x03G@u\x18\x00\x00\x00\x00\x00K\x04G@\x7f\xa4\x00\x00\x00\x00\x00K\x05G@\x87\xbb\x00\x00\x00\x00\x00K\x06G@\x91\xcc@\x00\x00\x00\x00K\x07G@\x9a\xb2`\x00\x00\x00\x00K\x08G@\xa4\x05\xc8\x00\x00\x00\x00K\tG@\xae\x08\xac\x00\x10\xc6\xf8K\nG@\xb6\x86\x80\xff\xfb\xceBK\x0bG\x7f\xf8\x00\x00\x00\x00\x00\x00K\x0cG@Y\x00\x00\x00\x00\x00\x00K\rG@b\xc0\x00\x00\x00\x00\x00K\x0eG@l \x00\x00\x00\x00\x00K\x0fG@u\x18\x00\x00\x00\x00\x00K\x10G@\x7f\xa4\x00\x00\x00\x00\x00K\x11G@\x87\xbb\x00\x00\x00\x00\x00K\x12G@\x91\xcc@\x00\x00\x00\x00K\x13G@\x9a\xb2`\x00\x00\x00\x00K\x14G@\xa4\x05\xc8\x00\x00\x00\x00K\x15G@\xae\x08\xac\x00\x10\xc6\xf8K\x16G@\xb6\x86\x80\xff\xfb\xceBK\x17G\x7f\xf8\x00\x00\x00\x00\x00\x00u\x8c\treplicate\x94}\x94(K\x00K\x01K\x01K\x01K\x02K\x01K\x03K\x01K\x04K\x01K\x05K\x01K\x06K\x01K\x07K\x01K\x08K\x01K\tK\x01K\nK\x01K\x0bK\x01K\x0cK\x01K\rK\x01K\x0eK\x01K\x0fK\x01K\x10K\x01K\x11K\x01K\x12K\x01K\x13K\x01K\x14K\x01K\x15K\x01K\x16K\x01K\x17K\x02u\x8c\x05fastq\x94}\x94(K\x00\x8c\x8d/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d0_conc1_S4_R1_001.fastq.gz\x94K\x01\x8c\x8e/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d0_conc2_S12_R1_001.fastq.gz\x94K\x02\x8c\x8e/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d0_conc3_S20_R1_001.fastq.gz\x94K\x03\x8c\x8e/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d0_conc4_S28_R1_001.fastq.gz\x94K\x04\x8c\x8e/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d0_conc5_S36_R1_001.fastq.gz\x94K\x05\x8c\x8e/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d0_conc6_S44_R1_001.fastq.gz\x94K\x06\x8c\x8e/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d0_conc7_S52_R1_001.fastq.gz\x94K\x07\x8c\x8e/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d0_conc8_S60_R1_001.fastq.gz\x94K\x08\x8c\x8e/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d0_conc9_S68_R1_001.fastq.gz\x94K\t\x8c\x8f/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d0_conc10_S76_R1_001.fastq.gz\x94K\n\x8c\x8f/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d0_conc11_S84_R1_001.fastq.gz\x94K\x0b\x8c\x90/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d0_noSerum_S92_R1_001.fastq.gz\x94K\x0c\x8c\x8e/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d28_conc1_S8_R1_001.fastq.gz\x94K\r\x8c\x8f/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d28_conc2_S16_R1_001.fastq.gz\x94K\x0e\x8c\x8f/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d28_conc3_S24_R1_001.fastq.gz\x94K\x0f\x8c\x8f/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d28_conc4_S32_R1_001.fastq.gz\x94K\x10\x8c\x8f/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d28_conc5_S40_R1_001.fastq.gz\x94K\x11\x8c\x8f/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d28_conc6_S48_R1_001.fastq.gz\x94K\x12\x8c\x8f/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d28_conc7_S56_R1_001.fastq.gz\x94K\x13\x8c\x8f/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d28_conc8_S64_R1_001.fastq.gz\x94K\x14\x8c\x8f/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d28_conc9_S72_R1_001.fastq.gz\x94K\x15\x8c\x90/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d28_conc10_S80_R1_001.fastq.gz\x94K\x16\x8c\x90/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d28_conc11_S88_R1_001.fastq.gz\x94K\x17\x8c\x91/fh/fast/bloom_j/SR/ngs/illumina/bloom_lab/240206_VH00699_434_AAFGTH5M5/Unaligned/Project_bloom_lab/rd512_A230212_d28_noSerum_S96_R1_001.fastq.gz\x94u\x8c\x0fserum_replicate\x94}\x94(K\x00j\x05\x01\x00\x00K\x01j\x05\x01\x00\x00K\x02j\x05\x01\x00\x00K\x03j\x05\x01\x00\x00K\x04j\x05\x01\x00\x00K\x05j\x05\x01\x00\x00K\x06j\x05\x01\x00\x00K\x07j\x05\x01\x00\x00K\x08j\x05\x01\x00\x00K\tj\x05\x01\x00\x00K\nj\x05\x01\x00\x00K\x0b\x8c\x06none-1\x94K\x0cj\x07\x01\x00\x00K\rj\x07\x01\x00\x00K\x0ej\x07\x01\x00\x00K\x0fj\x07\x01\x00\x00K\x10j\x07\x01\x00\x00K\x11j\x07\x01\x00\x00K\x12j\x07\x01\x00\x00K\x13j\x07\x01\x00\x00K\x14j\x07\x01\x00\x00K\x15j\x07\x01\x00\x00K\x16j\x07\x01\x00\x00K\x17\x8c\x06none-2\x94u\x8c\x0esample_noplate\x94}\x94(K\x00\x8c\x15A230212d0_rd512_100.0\x94K\x01\x8c\x15A230212d0_rd512_150.0\x94K\x02\x8c\x15A230212d0_rd512_225.0\x94K\x03\x8c\x15A230212d0_rd512_337.5\x94K\x04\x8c\x16A230212d0_rd512_506.25\x94K\x05\x8c\x17A230212d0_rd512_759.375\x94K\x06\x8c\x19A230212d0_rd512_1139.0625\x94K\x07\x8c\x1aA230212d0_rd512_1708.59375\x94K\x08\x8c\x1bA230212d0_rd512_2562.890625\x94K\t\x8c\x1bA230212d0_rd512_3844.335938\x94K\n\x8c\x1bA230212d0_rd512_5766.503906\x94K\x0bj(\x01\x00\x00K\x0c\x8c\x16A230212d28_rd512_100.0\x94K\r\x8c\x16A230212d28_rd512_150.0\x94K\x0e\x8c\x16A230212d28_rd512_225.0\x94K\x0f\x8c\x16A230212d28_rd512_337.5\x94K\x10\x8c\x17A230212d28_rd512_506.25\x94K\x11\x8c\x18A230212d28_rd512_759.375\x94K\x12\x8c\x1aA230212d28_rd512_1139.0625\x94K\x13\x8c\x1bA230212d28_rd512_1708.59375\x94K\x14\x8c\x1cA230212d28_rd512_2562.890625\x94K\x15\x8c\x1cA230212d28_rd512_3844.335938\x94K\x16\x8c\x1cA230212d28_rd512_5766.503906\x94K\x17j)\x01\x00\x00u\x8c\x06sample\x94}\x94(K\x00h\x93K\x01h\x94K\x02h\x95K\x03h\x96K\x04h\x97K\x05h\x98K\x06h\x99K\x07h\x9aK\x08h\x9bK\th\x9cK\nh\x9dK\x0bh\x9eK\x0ch\x9fK\rh\xa0K\x0eh\xa1K\x0fh\xa2K\x10h\xa3K\x11h\xa4K\x12h\xa5K\x13h\xa6K\x14h\xa7K\x15h\xa8K\x16h\xa9K\x17h\xaau\x8c\x05plate\x94}\x94(K\x00\x8c\x06plate7\x94K\x01jF\x01\x00\x00K\x02jF\x01\x00\x00K\x03jF\x01\x00\x00K\x04jF\x01\x00\x00K\x05jF\x01\x00\x00K\x06jF\x01\x00\x00K\x07jF\x01\x00\x00K\x08jF\x01\x00\x00K\tjF\x01\x00\x00K\njF\x01\x00\x00K\x0bjF\x01\x00\x00K\x0cjF\x01\x00\x00K\rjF\x01\x00\x00K\x0ejF\x01\x00\x00K\x0fjF\x01\x00\x00K\x10jF\x01\x00\x00K\x11jF\x01\x00\x00K\x12jF\x01\x00\x00K\x13jF\x01\x00\x00K\x14jF\x01\x00\x00K\x15jF\x01\x00\x00K\x16jF\x01\x00\x00K\x17jF\x01\x00\x00u\x8c\x0fplate_replicate\x94}\x94(K\x00jF\x01\x00\x00K\x01jF\x01\x00\x00K\x02jF\x01\x00\x00K\x03jF\x01\x00\x00K\x04jF\x01\x00\x00K\x05jF\x01\x00\x00K\x06jF\x01\x00\x00K\x07jF\x01\x00\x00K\x08jF\x01\x00\x00K\tjF\x01\x00\x00K\njF\x01\x00\x00K\x0b\x8c\x08plate7-1\x94K\x0cjF\x01\x00\x00K\rjF\x01\x00\x00K\x0ejF\x01\x00\x00K\x0fjF\x01\x00\x00K\x10jF\x01\x00\x00K\x11jF\x01\x00\x00K\x12jF\x01\x00\x00K\x13jF\x01\x00\x00K\x14jF\x01\x00\x00K\x15jF\x01\x00\x00K\x16jF\x01\x00\x00K\x17\x8c\x08plate7-2\x94uuue}\x94(h=}\x94(h\xe7K\x00N\x86\x94\x8c\x0cplate_params\x94K\x01N\x86\x94uhG]\x94(hIhJehIhMhO\x85\x94R\x94(hO)}\x94hShIsNt\x94bhJhMhO\x85\x94R\x94(hO)}\x94hShJsNt\x94bh\xe7h\x92jN\x01\x00\x00h\xabub\x8c\twildcards\x94h\x06\x8c\tWildcards\x94\x93\x94)\x81\x94\x8c\x06plate7\x94a}\x94(h=}\x94\x8c\x05plate\x94K\x00N\x86\x94shG]\x94(hIhJehIhMhO\x85\x94R\x94(hO)}\x94hShIsNt\x94bhJhMhO\x85\x94R\x94(hO)}\x94hShJsNt\x94bjD\x01\x00\x00j]\x01\x00\x00ub\x8c\x07threads\x94K\x01\x8c\tresources\x94h\x06\x8c\tResources\x94\x93\x94)\x81\x94(K\x01K\x01\x8c\x15/loc/scratch/64245082\x94e}\x94(h=}\x94(\x8c\x06_cores\x94K\x00N\x86\x94\x8c\x06_nodes\x94K\x01N\x86\x94\x8c\x06tmpdir\x94K\x02N\x86\x94uhG]\x94(hIhJehIhMhO\x85\x94R\x94(hO)}\x94hShIsNt\x94bhJhMhO\x85\x94R\x94(hO)}\x94hShJsNt\x94bjs\x01\x00\x00K\x01ju\x01\x00\x00K\x01jw\x01\x00\x00jp\x01\x00\x00ub\x8c\x03log\x94h\x06\x8c\x03Log\x94\x93\x94)\x81\x94\x8c*results/plates/plate7/process_plate7.ipynb\x94a}\x94(h=}\x94\x8c\x08notebook\x94K\x00N\x86\x94shG]\x94(hIhJehIhMhO\x85\x94R\x94(hO)}\x94hShIsNt\x94bhJhMhO\x85\x94R\x94(hO)}\x94hShJsNt\x94bj\x89\x01\x00\x00j\x86\x01\x00\x00ub\x8c\x06config\x94}\x94(\x8c\x10seqneut-pipeline\x94\x8c\x10seqneut-pipeline\x94\x8c\x04docs\x94\x8c\x04docs\x94\x8c\x0bdescription\x94X\n\x01\x00\x00# Sequencing-based neutralization assays of 2023-2024 human serum samples versus H3N2 influenza libraries\n\nThe numerical data and computer code are at [https://github.com/jbloomlab/flu_seqneut_H3N2_2023-2024](https://github.com/jbloomlab/flu_seqneut_H3N2_2023-2024)\n\x94\x8c\x0fviral_libraries\x94}\x94(\x8c\x0cH3N2_library\x94\x8c)data/viral_libraries/2023_H3N2_Kikawa.csv\x94\x8c\x0cH1N1_library\x94\x8c-data/viral_libraries/pdmH1N1_lib2023_loes.csv\x94u\x8c\x17viral_strain_plot_order\x94\x8c)data/H3N2library_2023-2024_allStrains.csv\x94\x8c\x12neut_standard_sets\x94}\x94\x8c\x08loes2023\x94\x8c3data/neut_standard_sets/loes2023_neut_standards.csv\x94s\x8c\x1eillumina_barcode_parser_params\x94}\x94(h\xdfh\xe0h\xe1h\xe2h\xe3K\x14h\xe4K\x04h\xe5h\xe6u\x8c#default_process_plate_qc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c%default_process_plate_curvefit_params\x94}\x94(h\xccK\x01h\xcd]\x94(G?\xe3333333K\x01eh\xcfK\x00h\xd0]\x94(G?\xe9\x99\x99\x99\x99\x99\x9aK\neu\x8c!default_process_plate_curvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9]\x94h\xdb]\x94u\x8c\x16default_serum_titer_as\x94\x8c\x08midpoint\x94\x8c\x1bdefault_serum_qc_thresholds\x94}\x94(\x8c\x0emin_replicates\x94K\x02\x8c\x1bmax_fold_change_from_median\x94K\x06\x8c\x11viruses_ignore_qc\x94]\x94u\x8c\x16sera_override_defaults\x94}\x94\x8c\x06plates\x94}\x94(\x8c\x06plate1\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94\x8c\x08datetime\x94\x8c\x04date\x94\x93\x94C\x04\x07\xe8\x01\x19\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-01-22_plate_mapping_file2.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x06plate2\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x01\x19\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-01-22_plate_mapping_file1.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x06plate3\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x01\x19\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-01-22_plate_mapping_file3.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\x18barcode_serum_replicates\x94]\x94(]\x94(\x8c\x10AATGACAGCTGTCTAG\x94\x8c\x12A230212d0_r64_rep1\x94e]\x94(\x8c\x10ATAGAAAATTATCCGC\x94\x8c\x12A230212d0_r64_rep1\x94ees\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x06plate4\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x02\x07\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-02-07_plate_mapping_file7.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x06plate5\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x02\x07\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-02-07_plate_mapping_file4.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x06plate6\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x02\x07\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-02-07_plate_mapping_file5.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uujF\x01\x00\x00}\x94(h\xach\xadh\xaej\xca\x01\x00\x00C\x04\x07\xe8\x02\x07\x94\x85\x94R\x94h\xb0h\xb1h\xb2h\xb3h\xb4h\xb5h\xb6}\x94h\xb8}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06uh\xca}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00uh\xd2}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x0eplate8_r32_50k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x03\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-03-04_plate_mapping_file10.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x0eplate9_r64_50k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x03\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-03-04_plate_mapping_file12.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x10plate10_r128_50k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x03\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-03-04_plate_mapping_file8.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x0fplate11_r32_75k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x03\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-03-04_plate_mapping_file11.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x0fplate12_r64_75k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x03\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-03-04_plate_mapping_file13.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x10plate13_r128_75k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x03\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c.data/plates/2024-03-04_plate_mapping_file9.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x07plate14\x94}\x94(\x8c\x05group\x94\x8c\x0eplatesToRepeat\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x03\x13\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-03-19_plate_mapping_file14.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rbarcode_wells\x94]\x94(]\x94(\x8c\x10AAGTATTGCTACACAT\x94\x8c\x02H3\x94e]\x94(\x8c\x10CCTATAAGGCCTTACG\x94\x8c\x02H3\x94ees\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x07plate15\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x03\x1c\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-03-28_plate_mapping_file15.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x07plate16\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x04\t\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-09_plate_mapping_file16.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x07plate17\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x04\x0b\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-11_plate_mapping_file17.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\x05wells\x94]\x94\x8c\x02A9\x94as\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x07plate18\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x04\x0b\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-11_plate_mapping_file18.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x0cplate19_100k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x04\x10\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-23_plate_mapping_file21.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x0cplate20_150k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x04\x10\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-23_plate_mapping_file22.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x0cplate21_200k\x94}\x94(\x8c\x05group\x94\x8c\x05pilot\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x04\x10\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-23_plate_mapping_file23.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x07plate22\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x04\x12\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-18_plate_mapping_file19.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06TGACGC\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate23\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x04\x12\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-04-18_plate_mapping_file20.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06CAGTTG\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate24\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x05\x02\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-02_plate_mapping_file24.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00uu\x8c\x07plate25\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x05\x14\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-20_plate_mapping_file27.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06TGACGC\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate26\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x05\x14\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-20_plate_mapping_file28.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06CAGTTG\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate27\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x05\x11\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-17_plate_mapping_file26.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?PbM\xd2\xf1\xa9\xfch\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06GCTACA\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate28\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x05\x11\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-17_plate_mapping_file25.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?PbM\xd2\xf1\xa9\xfch\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06ATCGAT\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate29\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x05\x1c\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-28_plate_mapping_file30.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06TGACGC\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate30\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x05\x1c\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-28_plate_mapping_file29.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06CAGTTG\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate31\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x05\x1e\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-30_plate_mapping_file31.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06GCTACA\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate32\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x05\x1e\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-05-30_plate_mapping_file32.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\x08barcodes\x94]\x94\x8c\x10CCAATCCCAGCCTTTA\x94as\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06ATCGAT\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate33\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x06\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-06-04_plate_mapping_file34.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06TGACGC\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate34\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x06\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-06-04_plate_mapping_file33.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06CAGTTG\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate35\x94}\x94(\x8c\x05group\x94\x8c\x11PennVaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x06\x04\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-07-02_plate_mapping_file36.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06ATCGAT\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate36\x94}\x94(\x8c\x05group\x94\x8c\x03SCH\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x05\x1e\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-07-02_plate_mapping_file35.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06TGACGC\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate37\x94}\x94(\x8c\x05group\x94\x8c\x11MA22VaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\t\x18\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-09-24_plate_mapping_file37.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06ATCGAT\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate38\x94}\x94(\x8c\x05group\x94\x8c\nPooledSera\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\t\x18\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-09-24_plate_mapping_file38.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06ATCGAT\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate39\x94}\x94(\x8c\x05group\x94\x8c\nPooledSera\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\t\x19\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-09-25_plate_mapping_file40.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06GCTACA\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate40\x94}\x94(\x8c\x05group\x94\x8c\x11MA22VaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\t\x19\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-09-25_plate_mapping_file41.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\x05wells\x94]\x94(\x8c\x03C10\x94\x8c\x03C11\x94es\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06GCTACA\x94\x8c\x12upstream2_mismatch\x94K\x01uu\x8c\x07plate41\x94}\x94(\x8c\x05group\x94\x8c\x11MA22VaccineCohort\x94\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\t\x19\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c/data/plates/2024-09-25_plate_mapping_file39.csv\x94\x8c\x0cmanual_drops\x94}\x94\x8c\rqc_thresholds\x94}\x94(h\xbaM\xf4\x01h\xbbG?tz\xe1G\xae\x14{h\xbc}\x94(h\xbeG?\x1a6\xe2\xeb\x1cC-h\xbfK\x04h\xc0K\x02uh\xc1}\x94(h\xc3G?tz\xe1G\xae\x14{h\xc4K\x04h\xc5K\x02uh\xc6M\xe8\x03h\xc7Kdh\xc8K\x03h\xc9K\x06u\x8c\x0fcurvefit_params\x94}\x94(h\xccK\x01h\xcdj\xb0\x01\x00\x00h\xcfK\x00h\xd0j\xb1\x01\x00\x00u\x8c\x0bcurvefit_qc\x94}\x94(h\xd4G\x00\x00\x00\x00\x00\x00\x00\x00h\xd5}\x94(h\xd7G?\xe0\x00\x00\x00\x00\x00\x00h\xd8G?\xc3333333uh\xd9j\xb5\x01\x00\x00h\xdbj\xb6\x01\x00\x00u\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06ATCGAT\x94\x8c\x12upstream2_mismatch\x94K\x01uuu\x8c\x14miscellaneous_plates\x94}\x94(\x8c\x13240111_initial_H3N2\x94}\x94(\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x01\x0b\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c=data/miscellaneous_plates/H3N2library_initialPool_samples.csv\x94u\x8c\x12240124_repool_H3N2\x94}\x94(\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x01\x18\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8cGdata/miscellaneous_plates/2024-01-22_H3N2_sampleData_rePool_MOItest.csv\x94u\x8c\x12240207_repool_H3N2\x94}\x94(\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x02\x07\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8cGdata/miscellaneous_plates/2024-02-07_H3N2_sampleData_rePool_MOItest.csv\x94u\x8c\x12240207_repool_H1N1\x94}\x94(\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x02\x07\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH1N1_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8cGdata/miscellaneous_plates/2024-02-07_H1N1_sampleData_rePool_MOItest.csv\x94u\x8c\x1f240328_repool_H3N2_variableCell\x94}\x94(\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\x03\x1c\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8cBdata/miscellaneous_plates/2024-03-28_H3N2_MOItest_variableCell.csv\x94u\x8c\x1c240924_repool_H3N2_balancing\x94}\x94(\x8c\x04date\x94j\xca\x01\x00\x00C\x04\x07\xe8\t\x18\x94\x85\x94R\x94\x8c\rviral_library\x94\x8c\x0cH3N2_library\x94\x8c\x11neut_standard_set\x94\x8c\x08loes2023\x94\x8c\x0bsamples_csv\x94\x8c>data/miscellaneous_plates/2024-09-24_repool_H3N2_balancing.csv\x94\x8c\x1eillumina_barcode_parser_params\x94}\x94(\x8c\tupstream2\x94\x8c\x06GCTACA\x94\x8c\x12upstream2_mismatch\x94K\x01uuuu\x8c\x04rule\x94\x8c\rprocess_plate\x94\x8c\x0fbench_iteration\x94N\x8c\tscriptdir\x94\x8ck/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/seqneut-pipeline/notebooks\x94ub.'); from snakemake.logging import logger; logger.printshellcmds = False; import os; os.chdir(r'/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024');
######## snakemake preamble end #########

Process plate counts to get fraction infectivities and fit curves¶

This notebook is designed to be run using snakemake, and analyzes a plate of sequencing-based neutralization assays.

The plots generated by this notebook are interactive, so you can mouseover points for details, use the mouse-scroll to zoom and pan, and use interactive dropdowns at the bottom of the plots.

Setup¶

Import Python modules:

In [2]:
import pickle
import sys

import altair as alt

import matplotlib.pyplot as plt

import neutcurve

import numpy

import pandas as pd

import ruamel.yaml as yaml

_ = alt.data_transformers.disable_max_rows()

Get the variables passed by snakemake:

In [3]:
count_csvs = snakemake.input.count_csvs
fate_csvs = snakemake.input.fate_csvs
viral_library_csv = snakemake.input.viral_library_csv
neut_standard_set_csv = snakemake.input.neut_standard_set_csv
qc_drops_yaml = snakemake.output.qc_drops
frac_infectivity_csv = snakemake.output.frac_infectivity_csv
fits_csv = snakemake.output.fits_csv
fits_pickle = snakemake.output.fits_pickle
samples = snakemake.params.samples
plate = snakemake.wildcards.plate
plate_params = snakemake.params.plate_params

# get thresholds turning lists into tuples as needed
manual_drops = {
    filter_type: [tuple(w) if isinstance(w, list) else w for w in filter_drops]
    for (filter_type, filter_drops) in plate_params["manual_drops"].items()
}
group = plate_params["group"]
qc_thresholds = plate_params["qc_thresholds"]
curvefit_params = plate_params["curvefit_params"]
curvefit_qc = plate_params["curvefit_qc"]
curvefit_qc["barcode_serum_replicates_ignore_curvefit_qc"] = [
    tuple(w) for w in curvefit_qc["barcode_serum_replicates_ignore_curvefit_qc"]
]

print(f"Processing {plate=}")

samples_df = pd.DataFrame(plate_params["samples"])
print(f"\nPlate has {len(samples)} samples (wells)")
assert all(
    (len(samples_df) == samples_df[c].nunique())
    for c in ["well", "sample", "sample_noplate"]
)
assert len(samples_df) == len(
    samples_df.groupby(["serum_replicate", "dilution_factor"])
)
assert len(samples) == len(count_csvs) == len(fate_csvs) == len(samples_df)

for d, key, title in [
    (manual_drops, "manual_drops", "Data manually specified to drop:"),
    (qc_thresholds, "qc_thresholds", "QC thresholds applied to data:"),
    (curvefit_params, "curvefit_params", "Curve-fitting parameters:"),
    (curvefit_qc, "curvefit_qc", "Curve-fitting QC:"),
]:
    print(f"\n{title}")
    yaml.YAML(typ="rt").dump({key: d}, stream=sys.stdout)
Processing plate='plate7'

Plate has 24 samples (wells)

Data manually specified to drop:
manual_drops: {}
QC thresholds applied to data:
qc_thresholds:
  avg_barcode_counts_per_well: 500
  min_neut_standard_frac_per_well: 0.005
  no_serum_per_viral_barcode_filters:
    min_frac: 0.0001
    max_fold_change: 4
    max_wells: 2
  per_neut_standard_barcode_filters:
    min_frac: 0.005
    max_fold_change: 4
    max_wells: 2
  min_neut_standard_count_per_well: 1000
  min_no_serum_count_per_viral_barcode_well: 100
  max_frac_infectivity_per_viral_barcode_well: 3
  min_dilutions_per_barcode_serum_replicate: 6
Curve-fitting parameters:
curvefit_params:
  frac_infectivity_ceiling: 1
  fixtop:
  - 0.6
  - 1
  fixbottom: 0
  fixslope:
  - 0.8
  - 10
Curve-fitting QC:
curvefit_qc:
  max_frac_infectivity_at_least: 0.0
  goodness_of_fit:
    min_R2: 0.5
    max_RMSD: 0.15
  serum_replicates_ignore_curvefit_qc: []
  barcode_serum_replicates_ignore_curvefit_qc: []

Set up dictionary to keep track of wells, barcodes, well-barcodes, and serum-replicates that are dropped:

In [4]:
qc_drops = {
    "wells": {},
    "barcodes": {},
    "barcode_wells": {},
    "barcode_serum_replicates": {},
    "serum_replicates": {},
}

assert set(manual_drops).issubset(
    qc_drops
), f"{manual_drops.keys()=}, {qc_drops.keys()}"

Statistics on barcode-parsing for each sample¶

Make interactive chart of the "fates" of the sequencing reads parsed for each sample on the plate.

If most sequencing reads are not "valid barcodes", this could potentially indicate some problem in the sequencing or barcode set you are parsing.

Potential fates are:

  • valid barcode: barcode that matches a known virus or neutralization standard, we hope most reads are this.
  • invalid barcode: a barcode with proper flanking sequences, but does not match a known virus or neutralization standard. If you have a lot of reads of this type, it is probably a good idea to look at the invalid barcode CSVs (in the ./results/barcode_invalid/ subdirectory created by the pipeline) to see what these invalid barcodes are.
  • unparseable barcode: could not parse a barcode from this read as there was not a sequence of the correct length with the appropriate flanking sequence.
  • invalid outer flank: if using an outer upstream or downstream region (upstream2 or downstream2 for the illuminabarcodeparser), reads that are otherwise valid except for this outer flank. Typically you would be using upstream2 if you have a plate index embedded in your primer, and reads with this classification correspond to a different index than the one for this plate.
  • low quality barcode: low-quality or N nucleotides in barcode, could indicate problem with sequencing.
  • failed chastity filter: reads that failed the Illumina chastity filter, if these are reported in the FASTQ (they may not be).

Also, if the number of reads per sample is very uneven, that could indicate that you did not do a good job of balancing the different samples in the Illumina sequencing.

In [5]:
fates = (
    pd.concat([pd.read_csv(f).assign(sample=s) for f, s in zip(fate_csvs, samples)])
    .merge(samples_df, validate="many_to_one", on="sample")
    .assign(
        fate_counts=lambda x: x.groupby("fate")["count"].transform("sum"),
        sample_well=lambda x: x["sample_noplate"] + " (" + x["well"] + ")",
    )
    .query("fate_counts > 0")[  # only keep fates with at least one count
        ["fate", "count", "well", "serum_replicate", "sample_well", "dilution_factor"]
    ]
)

assert len(fates) == len(fates.drop_duplicates())

serum_replicates = sorted(fates["serum_replicate"].unique())
sample_wells = list(
    fates.sort_values(["serum_replicate", "dilution_factor"])["sample_well"]
)


serum_selection = alt.selection_point(
    fields=["serum_replicate"],
    bind=alt.binding_select(
        options=[None] + serum_replicates,
        labels=["all"] + serum_replicates,
        name="serum",
    ),
)

fates_chart = (
    alt.Chart(fates)
    .add_params(serum_selection)
    .transform_filter(serum_selection)
    .encode(
        alt.X("count", scale=alt.Scale(nice=False, padding=3)),
        alt.Y(
            "sample_well",
            title=None,
            sort=sample_wells,
        ),
        alt.Color("fate", sort=sorted(fates["fate"].unique(), reverse=True)),
        alt.Order("fate", sort="descending"),
        tooltip=fates.columns.tolist(),
    )
    .mark_bar(height={"band": 0.85})
    .properties(
        height=alt.Step(10),
        width=200,
        title=f"Barcode parsing for {plate}",
    )
    .configure_axis(grid=False)
)

fates_chart
Out[5]:

Read barcode counts and apply manually specified drops¶

Read the counts per barcode:

In [6]:
# get barcode counts
counts = (
    pd.concat([pd.read_csv(c).assign(sample=s) for c, s in zip(count_csvs, samples)])
    .merge(samples_df, validate="many_to_one", on="sample")
    .drop(columns=["replicate", "plate", "fastq"])
    .assign(sample_well=lambda x: x["sample_noplate"] + " (" + x["well"] + ")")
)

# classify barcodes as viral or neut standard
barcode_class = pd.concat(
    [
        pd.read_csv(viral_library_csv)[["barcode", "strain"]].assign(
            neut_standard=False,
        ),
        pd.read_csv(neut_standard_set_csv)[["barcode"]].assign(
            neut_standard=True,
            strain=pd.NA,
        ),
    ],
    ignore_index=True,
)

# merge counts and classification of barcodes
assert set(counts["barcode"]) == set(barcode_class["barcode"])
counts = counts.merge(barcode_class, on="barcode", validate="many_to_one")
assert set(sample_wells) == set(counts["sample_well"])
assert set(serum_replicates) == set(counts["serum_replicate"])

Apply any manually specified data drops:

In [7]:
for filter_type, filter_drops in manual_drops.items():
    print(f"\nDropping {len(filter_drops)} {filter_type} specified in manual_drops")
    assert filter_type in qc_drops
    qc_drops[filter_type].update(
        {w: "manual_drop" for w in filter_drops if not isinstance(w, list)}
    )
    if filter_type == "barcode_wells":
        counts = counts[
            ~counts.assign(
                barcode_well=lambda x: x.apply(
                    lambda r: (r["barcode"], r["well"]), axis=1
                )
            )["barcode_well"].isin(qc_drops[filter_type])
        ]
    elif filter_type == "barcode_serum_replicates":
        counts = counts[
            ~counts.assign(
                barcode_serum_replicate=lambda x: x.apply(
                    lambda r: (r["barcode"], r["serum_replicate"]), axis=1
                )
            )["barcode_serum_replicate"].isin(qc_drops[filter_type])
        ]
    elif filter_type == "wells":
        counts = counts[~counts["well"].isin(qc_drops[filter_type])]
    elif filter_type == "barcodes":
        counts = counts[~counts["barcode"].isin(qc_drops[filter_type])]
    else:
        assert filter_type in set(counts.columns)
        counts = counts[~counts[filter_type].isin(qc_drops[filter_type])]

Average counts per barcode in each well¶

Plot average counts per barcode. If a sample has inadequate barcode counts, it may not have good enough statistics for accurate analysis, and a QC-threshold is applied:

In [8]:
avg_barcode_counts = (
    counts.groupby(
        ["well", "serum_replicate", "sample_well"],
        dropna=False,
        as_index=False,
    )
    .aggregate(avg_count=pd.NamedAgg("count", "mean"))
    .assign(
        fails_qc=lambda x: (
            x["avg_count"] < qc_thresholds["avg_barcode_counts_per_well"]
        ),
    )
)

avg_barcode_counts_chart = (
    alt.Chart(avg_barcode_counts)
    .add_params(serum_selection)
    .transform_filter(serum_selection)
    .encode(
        alt.X(
            "avg_count",
            title="average barcode counts per well",
            scale=alt.Scale(nice=False, padding=3),
        ),
        alt.Y("sample_well", sort=sample_wells),
        alt.Color(
            "fails_qc",
            title=f"fails {qc_thresholds['avg_barcode_counts_per_well']=}",
            legend=alt.Legend(titleLimit=500),
        ),
        tooltip=[
            alt.Tooltip(c, format=".3g") if avg_barcode_counts[c].dtype == float else c
            for c in avg_barcode_counts.columns
        ],
    )
    .mark_bar(height={"band": 0.85})
    .properties(
        height=alt.Step(10),
        width=250,
        title=f"Average barcode counts per well for {plate}",
    )
    .configure_axis(grid=False)
)

display(avg_barcode_counts_chart)

# drop wells failing QC
avg_barcode_counts_per_well_drops = list(avg_barcode_counts.query("fails_qc")["well"])
print(
    f"\nDropping {len(avg_barcode_counts_per_well_drops)} wells for failing "
    f"{qc_thresholds['avg_barcode_counts_per_well']=}: "
    + str(avg_barcode_counts_per_well_drops)
)
qc_drops["wells"].update(
    {w: "avg_barcode_counts_per_well" for w in avg_barcode_counts_per_well_drops}
)
counts = counts[~counts["well"].isin(qc_drops["wells"])]
Dropping 2 wells for failing qc_thresholds['avg_barcode_counts_per_well']=500: ['D7', 'H7']

Fraction of counts from neutralization standard¶

Determine the fraction of counts from the neutralization standard in each sample, and make sure this fraction passess the QC threshold.

In [9]:
neut_standard_fracs = (
    counts.assign(
        neut_standard_count=lambda x: x["count"] * x["neut_standard"].astype(int)
    )
    .groupby(
        ["well", "serum_replicate", "sample_well"],
        dropna=False,
        as_index=False,
    )
    .aggregate(
        total_count=pd.NamedAgg("count", "sum"),
        neut_standard_count=pd.NamedAgg("neut_standard_count", "sum"),
    )
    .assign(
        neut_standard_frac=lambda x: x["neut_standard_count"] / x["total_count"],
        fails_qc=lambda x: (
            x["neut_standard_frac"] < qc_thresholds["min_neut_standard_frac_per_well"]
        ),
    )
)

neut_standard_fracs_chart = (
    alt.Chart(neut_standard_fracs)
    .add_params(serum_selection)
    .transform_filter(serum_selection)
    .encode(
        alt.X(
            "neut_standard_frac",
            title="frac counts from neutralization standard per well",
            scale=alt.Scale(nice=False, padding=3),
        ),
        alt.Y("sample_well", sort=sample_wells),
        alt.Color(
            "fails_qc",
            title=f"fails {qc_thresholds['min_neut_standard_frac_per_well']=}",
            legend=alt.Legend(titleLimit=500),
        ),
        tooltip=[
            alt.Tooltip(c, format=".3g") if neut_standard_fracs[c].dtype == float else c
            for c in neut_standard_fracs.columns
        ],
    )
    .mark_bar(height={"band": 0.85})
    .properties(
        height=alt.Step(10),
        width=250,
        title=f"Neutralization-standard fracs per well for {plate}",
    )
    .configure_axis(grid=False)
    .configure_legend(titleLimit=1000)
)

display(neut_standard_fracs_chart)

# drop wells failing QC
min_neut_standard_frac_per_well_drops = list(
    neut_standard_fracs.query("fails_qc")["well"]
)
print(
    f"\nDropping {len(min_neut_standard_frac_per_well_drops)} wells for failing "
    f"{qc_thresholds['min_neut_standard_frac_per_well']=}: "
    + str(min_neut_standard_frac_per_well_drops)
)
qc_drops["wells"].update(
    {
        w: "min_neut_standard_frac_per_well"
        for w in min_neut_standard_frac_per_well_drops
    }
)
counts = counts[~counts["well"].isin(qc_drops["wells"])]
Dropping 0 wells for failing qc_thresholds['min_neut_standard_frac_per_well']=0.005: []

Consistency and minimum fractions for barcodes¶

We examine the fraction of counts attributable to each barcode. We do this splitting the data two ways:

  1. Looking at all viral (but not neut-standard) barcodes only for the no-serum samples (wells).

  2. Looking at just the neut-standard barcodes for all samples (wells).

The reasons is that if the experiment is set up perfectly, these fractions should be the same across all samples for each barcode. (We do not expect viral barcodes to have consistent fractions across no-serum samples as they will be neutralized differently depending on strain).

We plot these fractions in interactive plots (you can mouseover points and zoom) so you can identify barcodes that fail the expected consistency QC thresholds.

We also make sure the barcodes meet specified QC minimum thresholds for all samples, and flag any that do not.

In [10]:
barcode_selection = alt.selection_point(fields=["barcode"], on="mouseover", empty=False)

# look at all samples for neut standard barcodes, or no-serum samples for all barcodes
for is_neut_standard, df in counts.groupby("neut_standard"):
    if is_neut_standard:
        print(
            f"\n\n{'=' * 89}\nAnalyzing neut-standard barcodes from all samples (wells)"
        )
        qc_name = "per_neut_standard_barcode_filters"
    else:
        print(f"\n\n{'=' * 89}\nAnalyzing all barcodes from no-serum samples (wells)")
        qc_name = "no_serum_per_viral_barcode_filters"
        df = df.query("serum == 'none'")

    df = df.assign(
        sample_counts=lambda x: x.groupby("sample")["count"].transform("sum"),
        count_frac=lambda x: x["count"] / x["sample_counts"],
        median_count_frac=lambda x: x.groupby("barcode")["count_frac"].transform(
            "median"
        ),
        fold_change_from_median=lambda x: numpy.where(
            x["count_frac"] > x["median_count_frac"],
            x["count_frac"] / x["median_count_frac"],
            x["median_count_frac"] / x["count_frac"],
        ),
    )[
        [
            "barcode",
            "count",
            "well",
            "sample_well",
            "count_frac",
            "median_count_frac",
            "fold_change_from_median",
        ]
        + ([] if is_neut_standard else ["strain"])
    ]

    # barcode fails QC if fails in sufficient wells
    qc = qc_thresholds[qc_name]
    print(f"Apply QC {qc_name}: {qc}\n")
    fails_qc = (
        df.assign(
            fails_qc=lambda x: ~(
                (x["count_frac"] >= qc["min_frac"])
                & (x["fold_change_from_median"] <= qc["max_fold_change"])
            ),
        )
        .groupby("barcode", as_index=False)
        .aggregate(n_wells_fail_qc=pd.NamedAgg("fails_qc", "sum"))
        .assign(fails_qc=lambda x: x["n_wells_fail_qc"] >= qc["max_wells"])[
            ["barcode", "fails_qc"]
        ]
    )
    df = df.merge(fails_qc, on="barcode", validate="many_to_one")

    # make chart
    evenness_chart = (
        alt.Chart(df)
        .add_params(barcode_selection)
        .encode(
            alt.X(
                "count_frac",
                title=(
                    "barcode's fraction of neut standard counts"
                    if is_neut_standard
                    else "barcode's fraction of non-neut standard counts"
                ),
                scale=alt.Scale(nice=False, padding=5),
            ),
            alt.Y("sample_well", sort=sample_wells),
            alt.Fill(
                "fails_qc",
                title=f"fails {qc_name}",
                legend=alt.Legend(titleLimit=500),
            ),
            strokeWidth=alt.condition(barcode_selection, alt.value(2), alt.value(0)),
            size=alt.condition(barcode_selection, alt.value(60), alt.value(35)),
            tooltip=[
                alt.Tooltip(c, format=".2g") if df[c].dtype == float else c
                for c in df.columns
            ],
        )
        .mark_circle(fillOpacity=0.45, stroke="black", strokeOpacity=1)
        .properties(
            height=alt.Step(10),
            width=300,
            title=alt.TitleParams(
                (
                    f"{plate} all samples, neut-standard barcodes"
                    if is_neut_standard
                    else f"{plate} no-serum samples, all barcodes"
                ),
                subtitle="x-axis is zoomable (use mouse scroll/pan)",
            ),
        )
        .configure_axis(grid=False)
        .configure_legend(titleLimit=1000)
        .interactive()
    )

    display(evenness_chart)

    # drop barcodes failing QC
    barcode_drops = list(fails_qc.query("fails_qc")["barcode"])
    print(
        f"\nDropping {len(barcode_drops)} barcodes for failing {qc=}: {barcode_drops}"
    )
    qc_drops["barcodes"].update(
        {bc: "min_neut_standard_frac_per_well" for bc in barcode_drops}
    )
    counts = counts[~counts["barcode"].isin(qc_drops["barcodes"])]

=========================================================================================
Analyzing all barcodes from no-serum samples (wells)
Apply QC no_serum_per_viral_barcode_filters: {'min_frac': 0.0001, 'max_fold_change': 4, 'max_wells': 2}

Dropping 34 barcodes for failing qc={'min_frac': 0.0001, 'max_fold_change': 4, 'max_wells': 2}: ['AAAGTAGCAGAGGATT', 'AAATTCACAATATCCA', 'AACAATTAATTTTTCA', 'AAGTTGTACTTAAGGC', 'AATAGGCCCAAATCCA', 'AATTAATGGTAATAAA', 'ACAAAGATAAAAATTT', 'AGAAAAACGACATCAT', 'AGACCATCGCACCCAA', 'AGTGCTATAAAAATCA', 'ATAACGTTTGTGCAAA', 'ATCGATTCGATTGACG', 'ATGCGTCTAAACATAG', 'CAAAAGCAGCACGATA', 'CAAGACAAGCCCTATA', 'CAGATAGTGATGAACA', 'CATAAAAGACTGTATA', 'CCAATCCCAGCCTTTA', 'CCCTCCTCAAGGGTAA', 'CCTATAAGGCCTTACG', 'CGTACGTATGTCCCAG', 'CGTCCCTGGCGTGTCG', 'CGTTAACGGCCTATCC', 'CTCCAATAGGAGACGA', 'GCTGAAGACAGTATTA', 'GTAATTCGCATGCGGA', 'TATATGGAATACTAAA', 'TCGTCCTAGAACCTAA', 'TCTCCGATAGCCCTAC', 'TGGCTAGCGCACACCA', 'TGTTGTAATCTGAATA', 'TTACATTTTTAGAATT', 'TTATGTTTTAATGGTA', 'TTGCTAGTCTACCTGA']


=========================================================================================
Analyzing neut-standard barcodes from all samples (wells)
Apply QC per_neut_standard_barcode_filters: {'min_frac': 0.005, 'max_fold_change': 4, 'max_wells': 2}

Dropping 0 barcodes for failing qc={'min_frac': 0.005, 'max_fold_change': 4, 'max_wells': 2}: []

Compute fraction infectivity¶

The fraction infectivity for viral barcode $v_b$ in sample $s$ is computed as: $$ F_{v_b,s} = \frac{c_{v_b,s} / \left(\sum_{n_b} c_{n_b,s}\right)}{{\rm median}_{s_0}\left[ c_{v_b,s_0} / \left(\sum_{n_b} c_{n_b,s_0}\right)\right]} $$ where

  • $c_{v_b,s}$ is the counts of viral barcode $v_b$ in sample $s$.
  • $\sum_{n_b} c_{n_b,s}$ is the sum of the counts for all neutralization standard barcodes $n_b$ for sample $s$.
  • $c_{v_b,s_0}$ is the counts of viral barcode $v_b$ in no-serum sample $s_0$.
  • $\sum_{n_b} c_{n_b,s_0}$ is the sum of the counts for all neutralization standard barcodes $n_b$ for no-serum sample $s_0$.
  • ${\rm median}_{s_0}\left[ c_{v_b,s_0} / \left(\sum_{n_b} c_{n_b,s_0}\right)\right]$ is the median taken across all no-serum samples of the counts of viral barcode $v_b$ versus the total counts for all neutralization standard barcodes.

First, compute the total neutralization-standard counts for each sample (well). Plot these, and drop any wells that do not meet the QC threshold.

In [11]:
neut_standard_counts = (
    counts.query("neut_standard")
    .groupby(
        ["well", "serum_replicate", "sample_well", "dilution_factor"],
        dropna=False,
        as_index=False,
    )
    .aggregate(neut_standard_count=pd.NamedAgg("count", "sum"))
    .assign(
        fails_qc=lambda x: (
            x["neut_standard_count"] < qc_thresholds["min_neut_standard_count_per_well"]
        ),
    )
)

neut_standard_counts_chart = (
    alt.Chart(neut_standard_counts)
    .add_params(serum_selection)
    .transform_filter(serum_selection)
    .encode(
        alt.X(
            "neut_standard_count",
            title="counts from neutralization standard",
            scale=alt.Scale(nice=False, padding=3),
        ),
        alt.Y("sample_well", sort=sample_wells),
        alt.Color(
            "fails_qc",
            title=f"fails {qc_thresholds['min_neut_standard_count_per_well']=}",
            legend=alt.Legend(titleLimit=500),
        ),
        tooltip=[
            (
                alt.Tooltip(c, format=".3g")
                if neut_standard_counts[c].dtype == float
                else c
            )
            for c in neut_standard_counts.columns
        ],
    )
    .mark_bar(height={"band": 0.85})
    .properties(
        height=alt.Step(10),
        width=250,
        title=f"Neutralization-standard counts for {plate}",
    )
    .configure_axis(grid=False)
    .configure_legend(titleLimit=1000)
)

display(neut_standard_counts_chart)

# drop wells failing QC
min_neut_standard_count_per_well_drops = list(
    neut_standard_counts.query("fails_qc")["well"]
)
print(
    f"\nDropping {len(min_neut_standard_count_per_well_drops)} wells for failing "
    f"{qc_thresholds['min_neut_standard_count_per_well']=}: "
    + str(min_neut_standard_count_per_well_drops)
)
qc_drops["wells"].update(
    {
        w: "min_neut_standard_count_per_well"
        for w in min_neut_standard_count_per_well_drops
    }
)
neut_standard_counts = neut_standard_counts[
    ~neut_standard_counts["well"].isin(qc_drops["wells"])
]
counts = counts[~counts["well"].isin(qc_drops["wells"])]
Dropping 0 wells for failing qc_thresholds['min_neut_standard_count_per_well']=1000: []

Compute and plot the no-serum sample viral barcode counts and check if they pass the QC filters.

In [12]:
no_serum_counts = (
    counts.query("serum == 'none'")
    .query("not neut_standard")
    .merge(neut_standard_counts, validate="many_to_one")[
        ["barcode", "strain", "well", "sample_well", "count", "neut_standard_count"]
    ]
    .assign(
        fails_qc=lambda x: (
            x["count"] <= qc_thresholds["min_no_serum_count_per_viral_barcode_well"]
        ),
    )
)

strains = sorted(no_serum_counts["strain"].unique())
strain_selection_dropdown = alt.selection_point(
    fields=["strain"],
    bind=alt.binding_select(
        options=[None] + strains,
        labels=["all"] + strains,
        name="virus strain",
    ),
)

# make chart
no_serum_counts_chart = (
    alt.Chart(no_serum_counts)
    .add_params(barcode_selection, strain_selection_dropdown)
    .transform_filter(strain_selection_dropdown)
    .encode(
        alt.X(
            "count", title="viral barcode count", scale=alt.Scale(nice=False, padding=5)
        ),
        alt.Y("sample_well", sort=sample_wells),
        alt.Fill(
            "fails_qc",
            title=f"fails {qc_thresholds['min_no_serum_count_per_viral_barcode_well']=}",
            legend=alt.Legend(titleLimit=500),
        ),
        strokeWidth=alt.condition(barcode_selection, alt.value(2), alt.value(0)),
        size=alt.condition(barcode_selection, alt.value(60), alt.value(35)),
        tooltip=no_serum_counts.columns.tolist(),
    )
    .mark_circle(fillOpacity=0.6, stroke="black", strokeOpacity=1)
    .properties(
        height=alt.Step(10),
        width=400,
        title=f"{plate} viral barcode counts in no-serum samples",
    )
    .configure_axis(grid=False)
    .configure_legend(titleLimit=1000)
    .interactive()
)

display(no_serum_counts_chart)

# drop barcode / wells failing QC
min_no_serum_count_per_viral_barcode_well_drops = list(
    no_serum_counts.query("fails_qc")[["barcode", "well"]].itertuples(
        index=False, name=None
    )
)
print(
    f"\nDropping {len(min_no_serum_count_per_viral_barcode_well_drops)} barcode-wells for failing "
    f"{qc_thresholds['min_no_serum_count_per_viral_barcode_well']=}: "
    + str(min_no_serum_count_per_viral_barcode_well_drops)
)
qc_drops["barcode_wells"].update(
    {
        w: "min_no_serum_count_per_viral_barcode_well"
        for w in min_no_serum_count_per_viral_barcode_well_drops
    }
)
no_serum_counts = no_serum_counts[
    ~no_serum_counts.assign(
        barcode_well=lambda x: x.apply(lambda r: (r["barcode"], r["well"]), axis=1)
    )["barcode_well"].isin(qc_drops["barcode_wells"])
]
counts = counts[
    ~counts.assign(
        barcode_well=lambda x: x.apply(lambda r: (r["barcode"], r["well"]), axis=1)
    )["barcode_well"].isin(qc_drops["barcode_wells"])
]
Dropping 60 barcode-wells for failing qc_thresholds['min_no_serum_count_per_viral_barcode_well']=100: [('AATCCGGTTAACCCCG', 'D12'), ('TTTCATATAATTTGAG', 'D12'), ('AAAACAGGTCCGGTTT', 'D12'), ('GATCTGCTTGGAATGT', 'D12'), ('CCACAAGTTTGAAAAC', 'D12'), ('CGGGAATCTCCCATAC', 'D12'), ('ATTCAATACGTACTTA', 'D12'), ('CATAATGCACAAACGC', 'D12'), ('CCACGCACTTAAATAA', 'D12'), ('CCATCACCTTATACAC', 'D12'), ('CACCGACCAACTCTCT', 'D12'), ('TCCCGAACTGAACGCG', 'D12'), ('TTATAATGGCCGGTAT', 'D12'), ('AACGACACTTACATCC', 'D12'), ('AGACTGTACGCGACAG', 'D12'), ('GAAAGAAAGCTATATG', 'D12'), ('TACTGAGACACTTAAA', 'D12'), ('CGCGAACAACAGGGGA', 'D12'), ('GTTTTTCACTGAGTAG', 'D12'), ('AAAGACCTTTAACTCT', 'D12'), ('AAGCTAATCGTAGTCC', 'D12'), ('AATGACAGCTGTCTAG', 'D12'), ('ACGGACAACCTATCGC', 'D12'), ('CCGGTTTTCGGGACCT', 'D12'), ('CTACTAGAGCAGCGAG', 'D12'), ('CTCATTACAGAAATTG', 'D12'), ('CTTCATCTCATTTAAA', 'D12'), ('GACAGAAACAAAATTA', 'D12'), ('GTAGAAACTAGGAGTT', 'D12'), ('TAGTTGCCCCGACCTG', 'D12'), ('AGTTATGTAAAACGTG', 'H12'), ('AAGTATTGCTACACAT', 'H12'), ('AATCCGATAAGAGCTA', 'H12'), ('CGCAGTACACAACAAG', 'H12'), ('CCCGCTAACCCTGTCT', 'H12'), ('TTAGCTACTAACCCGT', 'H12'), ('ACGTAAATCCCCACAA', 'H12'), ('CACGTTAGTGAGACTT', 'H12'), ('CAGTAGCAAAACATGC', 'H12'), ('ACTATACATAGAAGAA', 'H12'), ('CCGCAATGACAATTTG', 'H12'), ('GACCTCCTGGGCACGC', 'H12'), ('TGCCGATCCAATTGAT', 'H12'), ('ACGCAAATAGACCGAA', 'H12'), ('AGGTGCGAGCCATCAG', 'H12'), ('TCCGCCACTATAACAT', 'H12'), ('CCAGAGACACGCTAGG', 'H12'), ('CACCCAAACGTTCGCA', 'H12'), ('CAATTCGCCGTTCCCC', 'H12'), ('CTACACTACATCAAAT', 'H12'), ('AATTACGCATAGGCCA', 'H12'), ('CCGCTATCATTAACCC', 'H12'), ('CTAAGGGCCTGTTCTT', 'H12'), ('AATGGTCGAGCCATTC', 'H12'), ('ATAGAAAATTATCCGC', 'H12'), ('CAGCCGCTAAAATGAT', 'H12'), ('CCTATTATAGCTAACA', 'H12'), ('CGATCTTTACGAAAAA', 'H12'), ('TAAACTGTAACTTACA', 'H12'), ('TGATCCGCAAGCTTAG', 'H12')]

Compute and plot the median ratio of viral barcode count to neut standard counts across no-serum samples. If library composition is equal, all of these values should be similar:

In [13]:
median_no_serum_ratio = (
    no_serum_counts.assign(ratio=lambda x: x["count"] / x["neut_standard_count"])
    .groupby(["barcode", "strain"], as_index=False)
    .aggregate(median_no_serum_ratio=pd.NamedAgg("ratio", "median"))
)

strain_selection = alt.selection_point(fields=["strain"], on="mouseover", empty=False)

median_no_serum_ratio_chart = (
    alt.Chart(median_no_serum_ratio)
    .add_params(strain_selection)
    .encode(
        alt.X(
            "median_no_serum_ratio",
            title="median ratio of counts",
            scale=alt.Scale(nice=False, padding=5),
        ),
        alt.Y(
            "barcode",
            sort=alt.SortField("median_no_serum_ratio", order="descending"),
            axis=alt.Axis(labelFontSize=5),
        ),
        color=alt.condition(strain_selection, alt.value("orange"), alt.value("gray")),
        tooltip=[
            (
                alt.Tooltip(c, format=".3g")
                if median_no_serum_ratio[c].dtype == float
                else c
            )
            for c in median_no_serum_ratio.columns
        ],
    )
    .mark_bar(height={"band": 0.85})
    .properties(
        height=alt.Step(5),
        width=250,
        title=f"{plate} no-serum median ratio viral barcode to neut-standard barcode",
    )
    .configure_axis(grid=False)
    .configure_legend(titleLimit=1000)
)

display(median_no_serum_ratio_chart)

Compute the actual fraction infectivities. We compute both the raw fraction infectivities and the ones with the ceiling applied:

In [14]:
frac_infectivity = (
    counts.query("not neut_standard")
    .query("serum != 'none'")
    .merge(median_no_serum_ratio, validate="many_to_one")
    .merge(neut_standard_counts, validate="many_to_one")
    .assign(
        frac_infectivity_raw=lambda x: (
            (x["count"] / x["neut_standard_count"]) / x["median_no_serum_ratio"]
        ),
        frac_infectivity_ceiling=lambda x: x["frac_infectivity_raw"].clip(
            upper=curvefit_params["frac_infectivity_ceiling"]
        ),
        concentration=lambda x: 1 / x["dilution_factor"],
        plate_barcode=lambda x: x["plate_replicate"] + "-" + x["barcode"],
    )[
        [
            "barcode",
            "plate_barcode",
            "well",
            "strain",
            "serum",
            "serum_replicate",
            "dilution_factor",
            "concentration",
            "frac_infectivity_raw",
            "frac_infectivity_ceiling",
        ]
    ]
)

assert len(
    frac_infectivity.groupby(["serum", "plate_barcode", "dilution_factor"])
) == len(frac_infectivity)
assert frac_infectivity["dilution_factor"].notnull().all()
assert frac_infectivity["frac_infectivity_raw"].notnull().all()
assert frac_infectivity["frac_infectivity_ceiling"].notnull().all()

Plot the fraction infectivities, both the raw values and with the ceiling applied:

In [15]:
frac_infectivity_chart_df = (
    frac_infectivity.assign(
        fails_qc=lambda x: (
            x["frac_infectivity_raw"]
            > qc_thresholds["max_frac_infectivity_per_viral_barcode_well"]
        ),
    )
    .melt(
        id_vars=[
            "barcode",
            "strain",
            "well",
            "serum_replicate",
            "dilution_factor",
            "fails_qc",
        ],
        value_vars=["frac_infectivity_raw", "frac_infectivity_ceiling"],
        var_name="ceiling_applied",
        value_name="frac_infectivity",
    )
    .assign(
        ceiling_applied=lambda x: x["ceiling_applied"].map(
            {
                "frac_infectivity_raw": "raw fraction infectivity",
                "frac_infectivity_ceiling": f"fraction infectivity with ceiling at {curvefit_params['frac_infectivity_ceiling']}",
            }
        )
    )
)

frac_infectivity_chart = (
    alt.Chart(frac_infectivity_chart_df)
    .add_params(strain_selection_dropdown, barcode_selection)
    .transform_filter(strain_selection_dropdown)
    .encode(
        alt.X(
            "dilution_factor",
            title="dilution factor",
            scale=alt.Scale(nice=False, padding=5, type="log"),
        ),
        alt.Y(
            "frac_infectivity",
            title="fraction infectivity",
            scale=alt.Scale(nice=False, padding=5),
        ),
        alt.Column(
            "ceiling_applied",
            sort="descending",
            title=None,
            header=alt.Header(labelFontSize=13, labelFontStyle="bold", labelPadding=2),
        ),
        alt.Row(
            "serum_replicate",
            title=None,
            spacing=3,
            header=alt.Header(labelFontSize=13, labelFontStyle="bold"),
        ),
        alt.Detail("barcode"),
        alt.Shape(
            "fails_qc",
            title=f"fails {qc_thresholds['max_frac_infectivity_per_viral_barcode_well']=}",
            legend=alt.Legend(titleLimit=500, orient="bottom"),
        ),
        color=alt.condition(
            barcode_selection, alt.value("black"), alt.value("MediumBlue")
        ),
        strokeWidth=alt.condition(barcode_selection, alt.value(3), alt.value(1)),
        opacity=alt.condition(barcode_selection, alt.value(1), alt.value(0.25)),
        tooltip=[
            (
                alt.Tooltip(c, format=".3g")
                if frac_infectivity_chart_df[c].dtype == float
                else c
            )
            for c in frac_infectivity_chart_df.columns
        ],
    )
    .mark_line(point=True)
    .properties(
        height=150,
        width=250,
        title=f"Fraction infectivities for {plate}",
    )
    .interactive(bind_x=False)
    .configure_axis(grid=False)
    .configure_legend(titleLimit=1000)
    .configure_point(size=50)
    .resolve_scale(x="independent", y="independent")
)

display(frac_infectivity_chart)

# drop barcode / wells failing QC
max_frac_infectivity_per_viral_barcode_well_drops = list(
    frac_infectivity_chart_df.query("fails_qc")[["barcode", "well"]]
    .drop_duplicates()
    .itertuples(index=False, name=None)
)
print(
    f"\nDropping {len(max_frac_infectivity_per_viral_barcode_well_drops)} barcode-wells for failing "
    f"{qc_thresholds['max_frac_infectivity_per_viral_barcode_well']=}: "
    + str(max_frac_infectivity_per_viral_barcode_well_drops)
)
qc_drops["barcode_wells"].update(
    {
        w: "max_frac_infectivity_per_viral_barcode_well"
        for w in max_frac_infectivity_per_viral_barcode_well_drops
    }
)
frac_infectivity = frac_infectivity[
    ~frac_infectivity.assign(
        barcode_well=lambda x: x.apply(lambda r: (r["barcode"], r["well"]), axis=1)
    )["barcode_well"].isin(qc_drops["barcode_wells"])
]
Dropping 195 barcode-wells for failing qc_thresholds['max_frac_infectivity_per_viral_barcode_well']=3: [('TAGCTGGGCAAAGGCT', 'D2'), ('GACCAAAGCTGCAGGG', 'D2'), ('TAGTTGCCCCGACCTG', 'D2'), ('TAGATAATAAGATTCA', 'D3'), ('GACAGAAACAAAATTA', 'D4'), ('AAATACCCTTGAGATA', 'D4'), ('ATCGTCCCGGACATTT', 'D4'), ('ATGGTTATCTTACCTT', 'D4'), ('TCTTGAATTTCATGGA', 'D4'), ('TATTATCTAAACGGCG', 'D5'), ('GTTTTTCACTGAGTAG', 'D5'), ('ACCCTTTTAGATATGA', 'D5'), ('ACTATACATAGAAGAA', 'D5'), ('GCCCATTGAACGCAGC', 'D5'), ('CTATCTTAATCTACAG', 'D5'), ('TCAAACTATGATATTC', 'D5'), ('ACCGTTTTTCTACCAG', 'D5'), ('CCCGCTAACCCTGTCT', 'D5'), ('CGCCGAACGGCGGCGC', 'D5'), ('ATCGTCCCGGACATTT', 'D5'), ('GAGATAGCCCAGAGGT', 'D6'), ('AACAAGGCCAACATTT', 'D6'), ('CCGCTATCATTAACCC', 'D6'), ('TACCATTTTGGTCCGC', 'D6'), ('CGCAAGGGATACTAAC', 'D6'), ('ATAAAGAATCCCTTGA', 'D6'), ('CCACAAGTTTGAAAAC', 'D6'), ('AAACTTCGTGGTATAC', 'D6'), ('CCATCACCTTATACAC', 'D6'), ('GATTCACGGCCCACAA', 'D6'), ('TGATTCGTCAATTCAT', 'D6'), ('TTTCATATAATTTGAG', 'D6'), ('TCTTGAATTTCATGGA', 'D6'), ('CTACACTACATCAAAT', 'D6'), ('GCAACGAGGTGTAACC', 'D8'), ('AACGACACTTACATCC', 'D8'), ('TTTCATATAATTTGAG', 'D8'), ('AAACTTCGTGGTATAC', 'D8'), ('ACGTAAATCCCCACAA', 'D8'), ('CCACAAGTTTGAAAAC', 'D8'), ('TCAACCCTTCGATGTA', 'D8'), ('GAAGTAACAAACTATG', 'D8'), ('GATTCACGGCCCACAA', 'D8'), ('TTGACTCACCGAATAA', 'D8'), ('CCCATATACTCACAGA', 'D8'), ('CCAATCATGTATCACA', 'D8'), ('AAGCGGTTTAGGTCCA', 'D8'), ('CCACAAGTTTGAAAAC', 'D9'), ('TCTTAACTACCCGATG', 'D9'), ('CCGATAAGACGTCGCT', 'D9'), ('TCTTGAATTTCATGGA', 'D9'), ('TCAACCCTTCGATGTA', 'D9'), ('AGTTATGTAAAACGTG', 'D9'), ('CTATCTTAATCTACAG', 'D9'), ('GCATTATAATCTTGTG', 'D9'), ('ATGGTTATCTTACCTT', 'D9'), ('TGATTCGTCAATTCAT', 'D9'), ('CTACACTACATCAAAT', 'D9'), ('GAAGTAACAAACTATG', 'D9'), ('CTTCATCTCATTTAAA', 'D9'), ('AGTTATGTAAAACGTG', 'D10'), ('CTTGAATACACAAACA', 'D10'), ('AATCTTTCCAATCTTG', 'D10'), ('CCATCACCTTATACAC', 'D10'), ('GGGTGCAATGAATCCA', 'D10'), ('TCTTGAATTTCATGGA', 'D10'), ('GACAGAAACAAAATTA', 'D10'), ('CTTACAAAGGTAATTC', 'D10'), ('TAGATAATAAGATTCA', 'D10'), ('CCGATAAGACGTCGCT', 'D10'), ('AAGCGGTTTAGGTCCA', 'D10'), ('CTATCTTAATCTACAG', 'D10'), ('CGCGAATCACTAAGTA', 'D10'), ('CTGTGAAAAAAAATAC', 'D10'), ('TGATTCGTCAATTCAT', 'D10'), ('CCAATCATGTATCACA', 'D10'), ('TTGACTCACCGAATAA', 'D10'), ('AACGACACTTACATCC', 'D10'), ('GAAAGAAAGCTATATG', 'D10'), ('CATAATGCACAAACGC', 'D10'), ('TTCATCAAGTTGGTGC', 'D11'), ('TCTTGAATTTCATGGA', 'D11'), ('CAAAAAGCTAATAAGT', 'D11'), ('CTTCATCTCATTTAAA', 'D11'), ('CACCACAGTTACTTAA', 'D11'), ('CCGATAAGACGTCGCT', 'D11'), ('CCACGCACTTAAATAA', 'D11'), ('TAGTTGCCCCGACCTG', 'D11'), ('AAATACCCTTGAGATA', 'D11'), ('AGTTATGTAAAACGTG', 'D11'), ('GCATTATAATCTTGTG', 'D11'), ('ATGGTTATCTTACCTT', 'D11'), ('GGCTATATATCTGTTT', 'D11'), ('CGCCGAACGGCGGCGC', 'D11'), ('GATTCACGGCCCACAA', 'D11'), ('CGCAAGGGATACTAAC', 'H2'), ('TGATTCGTCAATTCAT', 'H4'), ('CTTGAATACACAAACA', 'H4'), ('CTATCTTAATCTACAG', 'H4'), ('CACCACAGTTACTTAA', 'H4'), ('GAAAGAAAGCTATATG', 'H4'), ('CTGAAACCTTGTCCTA', 'H5'), ('TACCATTTTGGTCCGC', 'H5'), ('TGAGATCAGCCGGGTG', 'H5'), ('GGTTGCGTAGTTAATC', 'H5'), ('CTTACAAAGGTAATTC', 'H5'), ('CCCGCTAACCCTGTCT', 'H5'), ('CTGTGAAAAAAAATAC', 'H5'), ('GCTAATTCCAAAAGCG', 'H5'), ('TGTAGTATAAGAATAA', 'H5'), ('TCAACCCTTCGATGTA', 'H5'), ('AGTTATGTAAAACGTG', 'H5'), ('ACTATACATAGAAGAA', 'H5'), ('TCTTGAATTTCATGGA', 'H5'), ('TATTATCTAAACGGCG', 'H6'), ('GTTTTTCACTGAGTAG', 'H6'), ('AAGTGGTAGGATAAAA', 'H6'), ('TAGTTGCCCCGACCTG', 'H6'), ('CCACGCACTTAAATAA', 'H8'), ('GCCCATTGAACGCAGC', 'H8'), ('AAACTTCGTGGTATAC', 'H8'), ('AGATCATAAGCAATAA', 'H8'), ('TCTTGAATTTCATGGA', 'H8'), ('TAGATAATAAGATTCA', 'H8'), ('TAAAAGAATGATGGTC', 'H8'), ('CTTACAAAGGTAATTC', 'H8'), ('CACCACAGTTACTTAA', 'H8'), ('GAAGTAACAAACTATG', 'H8'), ('AACAAGGCCAACATTT', 'H8'), ('AAGCGGTTTAGGTCCA', 'H8'), ('TGACAAACACCTGAGG', 'H8'), ('ATAAAGAATCCCTTGA', 'H8'), ('GCTAATTCCAAAAGCG', 'H9'), ('GGGTGCAATGAATCCA', 'H9'), ('CGCGAATCACTAAGTA', 'H9'), ('TCCTTTAACTAATCGA', 'H9'), ('CTTACAAAGGTAATTC', 'H9'), ('TCAACCCTTCGATGTA', 'H9'), ('CAATGGATAATGATAG', 'H9'), ('AAACTTCGTGGTATAC', 'H9'), ('TAGATAATAAGATTCA', 'H9'), ('CCACAAGTTTGAAAAC', 'H9'), ('CACCTTCATCCTAAAG', 'H9'), ('AAATACCCTTGAGATA', 'H9'), ('TTTCATATAATTTGAG', 'H9'), ('TATCAATTCGGTATTA', 'H9'), ('TTAGCTACTAACCCGT', 'H9'), ('TGTAGTATAAGAATAA', 'H9'), ('CGCCGAACGGCGGCGC', 'H9'), ('TCTTGAATTTCATGGA', 'H9'), ('CTACACTACATCAAAT', 'H9'), ('GAAAGAAAGCTATATG', 'H9'), ('AAGTGGTAGGATAAAA', 'H10'), ('TACCATTTTGGTCCGC', 'H10'), ('GCTAATTCCAAAAGCG', 'H10'), ('TTGACTCACCGAATAA', 'H10'), ('CGCAAGGGATACTAAC', 'H10'), ('ACTATACATAGAAGAA', 'H10'), ('CTACACTACATCAAAT', 'H10'), ('TTTATGCCGATAGAGA', 'H10'), ('CAGTAGCAAAACATGC', 'H10'), ('CCACGCACTTAAATAA', 'H10'), ('CGCGAACAACAGGGGA', 'H10'), ('TCAACCCTTCGATGTA', 'H10'), ('AGTTATGTAAAACGTG', 'H10'), ('TAGTTGCCCCGACCTG', 'H10'), ('GTTTTTCACTGAGTAG', 'H10'), ('GCATTATAATCTTGTG', 'H10'), ('CGGCTAAAGTCTATAG', 'H10'), ('TTTCATATAATTTGAG', 'H10'), ('CCCATATACTCACAGA', 'H10'), ('GATTCACGGCCCACAA', 'H10'), ('GCTAATTCCAAAAGCG', 'H11'), ('GCAACGAGGTGTAACC', 'H11'), ('GACCTCCTGGGCACGC', 'H11'), ('CGTATAACTGACGATT', 'H11'), ('TAGTTGCCCCGACCTG', 'H11'), ('CCGCTATCATTAACCC', 'H11'), ('CGTACAGTGTAATCGA', 'H11'), ('GCTTTTGAGAACCATT', 'H11'), ('ATGGTTATCTTACCTT', 'H11'), ('GCCGTAGCGAAATCTT', 'H11'), ('AAAGATAAATTCAAAA', 'H11'), ('GCATTATAATCTTGTG', 'H11'), ('TACTGAGACACTTAAA', 'H11'), ('TAAAAGAATGATGGTC', 'H11'), ('CGCGAATCACTAAGTA', 'H11'), ('ACCGTTTTTCTACCAG', 'H11'), ('GTAGAAACTAGGAGTT', 'H11'), ('CGCGAACAACAGGGGA', 'H11'), ('CCAATCATGTATCACA', 'H11'), ('CATAATGCACAAACGC', 'H11'), ('CCGCAATGACAATTTG', 'H11'), ('TCTTGAATTTCATGGA', 'H11'), ('AAGCGGTTTAGGTCCA', 'H11')]

Check how many dilutions we have per barcode / serum-replicate:

In [16]:
n_dilutions = (
    frac_infectivity.groupby(["serum_replicate", "strain", "barcode"], as_index=False)
    .aggregate(**{"number of dilutions": pd.NamedAgg("dilution_factor", "nunique")})
    .assign(
        fails_qc=lambda x: (
            x["number of dilutions"]
            < qc_thresholds["min_dilutions_per_barcode_serum_replicate"]
        ),
    )
)

n_dilutions_chart = (
    alt.Chart(n_dilutions)
    .add_params(barcode_selection)
    .encode(
        alt.X("number of dilutions", scale=alt.Scale(nice=False, padding=4)),
        alt.Y("strain", title=None),
        alt.Column(
            "serum_replicate",
            title=None,
            header=alt.Header(labelFontSize=12, labelFontStyle="bold", labelPadding=0),
        ),
        alt.Fill(
            "fails_qc",
            title=f"fails {qc_thresholds['min_dilutions_per_barcode_serum_replicate']=}",
            legend=alt.Legend(titleLimit=500, orient="bottom"),
        ),
        strokeWidth=alt.condition(barcode_selection, alt.value(2), alt.value(0)),
        size=alt.condition(barcode_selection, alt.value(55), alt.value(35)),
        tooltip=[
            alt.Tooltip(c, format=".3g") if n_dilutions[c].dtype == float else c
            for c in n_dilutions.columns
        ],
    )
    .mark_circle(stroke="black", strokeOpacity=1, fillOpacity=0.45)
    .properties(
        height=alt.Step(10),
        width=120,
        title=alt.TitleParams(
            "number of dilutions for each barcode for each serum-replicate", dy=-2
        ),
    )
)

display(n_dilutions_chart)

# drop barcode / serum-replicates failing QC
min_dilutions_per_barcode_serum_replicate_drops = list(
    n_dilutions.query("fails_qc")[["barcode", "serum_replicate"]].itertuples(
        index=False, name=None
    )
)
print(
    f"\nDropping {len(min_dilutions_per_barcode_serum_replicate_drops)} barcode/serum-replicates for failing "
    f"{qc_thresholds['min_dilutions_per_barcode_serum_replicate']=}: "
    + str(min_dilutions_per_barcode_serum_replicate_drops)
)
qc_drops["barcode_serum_replicates"].update(
    {
        w: "min_dilutions_per_barcode_serum_replicate"
        for w in min_dilutions_per_barcode_serum_replicate_drops
    }
)
frac_infectivity = frac_infectivity[
    ~frac_infectivity.assign(
        barcode_serum_replicate=lambda x: x.apply(
            lambda r: (r["barcode"], r["serum_replicate"]), axis=1
        )
    )["barcode_serum_replicate"].isin(qc_drops["barcode_serum_replicates"])
]
Dropping 1 barcode/serum-replicates for failing qc_thresholds['min_dilutions_per_barcode_serum_replicate']=6: [('TCTTGAATTTCATGGA', 'A230212d0_rd512')]

Fit neutralization curves without applying QC to curves¶

First fit curves to all serum replicates, then we will apply QC on the curve fits. Note that the fitting is done to the fraction infectivities with the ceiling:

In [17]:
fits_noqc = neutcurve.CurveFits(
    frac_infectivity.rename(
        columns={
            "frac_infectivity_ceiling": "fraction infectivity",
            "concentration": "serum concentration",
        }
    ),
    conc_col="serum concentration",
    fracinf_col="fraction infectivity",
    virus_col="strain",
    serum_col="serum_replicate",
    replicate_col="barcode",
    fixtop=curvefit_params["fixtop"],
    fixbottom=curvefit_params["fixbottom"],
    fixslope=curvefit_params["fixslope"],
)

Determine which fits fail the curve fitting QC, and plot them. Note the plot indicates as failing QC any barcode / serum-replicate that fails, even if we are also specified to ignore the QC for that one (so it will not be removed later):

In [18]:
goodness_of_fit = curvefit_qc["goodness_of_fit"]

fit_params_noqc = (
    frac_infectivity.groupby(["serum_replicate", "barcode"], as_index=False)
    .aggregate(max_frac_infectivity=pd.NamedAgg("frac_infectivity_ceiling", "max"))
    .merge(
        fits_noqc.fitParams(average_only=False, no_average=True)[
            ["serum", "virus", "replicate", "r2", "rmsd"]
        ].rename(columns={"serum": "serum_replicate", "replicate": "barcode"}),
        validate="one_to_one",
    )
    .assign(
        fails_max_frac_infectivity_at_least=lambda x: (
            x["max_frac_infectivity"] < curvefit_qc["max_frac_infectivity_at_least"]
        ),
        fails_goodness_of_fit=lambda x: (
            (x["r2"] < goodness_of_fit["min_R2"])
            & (x["rmsd"] > goodness_of_fit["max_RMSD"])
        ),
        fails_qc=lambda x: (
            x["fails_max_frac_infectivity_at_least"] | x["fails_goodness_of_fit"]
        ),
        ignore_qc=lambda x: x.apply(
            lambda r: (
                (
                    r["serum_replicate"]
                    in curvefit_qc["serum_replicates_ignore_curvefit_qc"]
                )
                or (
                    (r["barcode"], r["serum_replicate"])
                    in curvefit_qc["barcode_serum_replicates_ignore_curvefit_qc"]
                )
            ),
            axis=1,
        ),
    )
)

print(f"Plotting barcode / serum-replicates that fail {curvefit_qc=}\n")

for prop, col in [
    ("max frac infectivity", "max_frac_infectivity"),
    ("curve fit R2", "r2"),
    ("curve fit RMSD", "rmsd"),
]:
    fit_params_noqc_chart = (
        alt.Chart(fit_params_noqc)
        .add_params(barcode_selection)
        .encode(
            alt.X(col, title=prop, scale=alt.Scale(nice=False, padding=4)),
            alt.Y("virus", title=None),
            alt.Fill("fails_qc"),
            alt.Column(
                "serum_replicate",
                title=None,
                header=alt.Header(
                    labelFontSize=12, labelFontStyle="bold", labelPadding=0
                ),
            ),
            strokeWidth=alt.condition(barcode_selection, alt.value(2), alt.value(0)),
            size=alt.condition(barcode_selection, alt.value(55), alt.value(35)),
            tooltip=[
                alt.Tooltip(c, format=".3g") if fit_params_noqc[c].dtype == float else c
                for c in fit_params_noqc.columns
            ],
        )
        .mark_circle(stroke="black", strokeOpacity=1, fillOpacity=0.55)
        .properties(
            height=alt.Step(10),
            width=120,
            title=alt.TitleParams(f"{prop} for each barcode serum-replicate", dy=-2),
        )
    )
    display(fit_params_noqc_chart)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:469: UserWarning: `f` increases with concentration, consider `infectivity_or_neutralized="neutralized"
  warnings.warn(
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
Plotting barcode / serum-replicates that fail curvefit_qc={'max_frac_infectivity_at_least': 0.0, 'goodness_of_fit': {'min_R2': 0.5, 'max_RMSD': 0.15}, 'serum_replicates_ignore_curvefit_qc': [], 'barcode_serum_replicates_ignore_curvefit_qc': []}

Now get all barcode / serum-replicate pairs that fail any of the QC. Plot curves for just these virus / serum-replicates (we plot all barcodes for a virus even if just one fails QC), and then exclude any that are not specified to ignore the QC:

In [19]:
barcode_serum_replicates_fail_qc = fit_params_noqc.query("fails_qc").reset_index(
    drop=True
)
print(f"Here are barcode / serum-replicates that fail {curvefit_qc=}")
display(barcode_serum_replicates_fail_qc)

if len(barcode_serum_replicates_fail_qc):
    print("\nCurves for viruses and serum-replicates with at least one failed barcode:")
    fig, _ = fits_noqc.plotReplicates(
        sera=sorted(barcode_serum_replicates_fail_qc["serum_replicate"].unique()),
        viruses=sorted(barcode_serum_replicates_fail_qc["virus"].unique()),
        attempt_shared_legend=False,
        legendfontsize=8,
        titlesize=10,
        ticksize=10,
        ncol=6,
        draw_in_bounds=True,
    )
    display(fig)
    plt.close(fig)

# drop barcode / serum-replicates failing QC
for qc_filter in ["max_frac_infectivity_at_least", "goodness_of_fit"]:
    fits_qc_drops = list(
        fit_params_noqc.query(f"fails_{qc_filter} and (not ignore_qc)")[
            ["barcode", "serum_replicate"]
        ].itertuples(index=False, name=None)
    )
    print(
        f"\nDropping {len(fits_qc_drops)} barcode/serum-replicates for failing "
        f"{qc_filter}={curvefit_qc[qc_filter]}: " + str(fits_qc_drops)
    )
    qc_drops["barcode_serum_replicates"].update({w: qc_filter for w in fits_qc_drops})
    frac_infectivity = frac_infectivity[
        ~frac_infectivity.assign(
            barcode_serum_replicate=lambda x: x.apply(
                lambda r: (r["barcode"], r["serum_replicate"]), axis=1
            )
        )["barcode_serum_replicate"].isin(qc_drops["barcode_serum_replicates"])
    ]
    fit_params_noqc = fit_params_noqc[
        ~fit_params_noqc.assign(
            barcode_serum_replicate=lambda x: x.apply(
                lambda r: (r["barcode"], r["serum_replicate"]), axis=1
            )
        )["barcode_serum_replicate"].isin(qc_drops["barcode_serum_replicates"])
    ]
Here are barcode / serum-replicates that fail curvefit_qc={'max_frac_infectivity_at_least': 0.0, 'goodness_of_fit': {'min_R2': 0.5, 'max_RMSD': 0.15}, 'serum_replicates_ignore_curvefit_qc': [], 'barcode_serum_replicates_ignore_curvefit_qc': []}
serum_replicate barcode max_frac_infectivity virus r2 rmsd fails_max_frac_infectivity_at_least fails_goodness_of_fit fails_qc ignore_qc
0 A230212d0_rd512 AAAACAGGTCCGGTTT 1.000000 A/SouthAfrica/PET28931/2023 0.251701 0.303650 False True True False
1 A230212d0_rd512 AAATACCCTTGAGATA 0.528648 A/South_Africa/R06506/2023 0.142150 0.158431 False True True False
2 A230212d0_rd512 AAGTGGTAGGATAAAA 1.000000 A/South_Africa/R06506/2023 -0.101322 0.310345 False True True False
3 A230212d0_rd512 AATGACAGCTGTCTAG 0.852344 A/Sydney/715/2023 0.413007 0.228149 False True True False
4 A230212d0_rd512 ACAGTACAGATATGAC 1.000000 A/Townsville/68/2023 0.478117 0.230345 False True True False
... ... ... ... ... ... ... ... ... ... ...
137 A230212d28_rd512 TTAGCAGTTAACGTAT 0.788426 A/YAMAGATA/98/2023 0.122278 0.270607 False True True False
138 A230212d28_rd512 TTAGTCATCTGGGTGC 0.782900 A/SouthSudan/631/2023 -0.139143 0.251537 False True True False
139 A230212d28_rd512 TTATAATGGCCGGTAT 1.000000 A/EHIME/50/2023 -0.086251 0.349825 False True True False
140 A230212d28_rd512 TTGCAATTGAAACATA 1.000000 A/Cambodia/e0826360/2020 0.284349 0.279184 False True True False
141 A230212d28_rd512 TTTATGCCGATAGAGA 1.000000 A/South_Africa/R05384/2023 0.451816 0.227628 False True True False

142 rows × 10 columns

Curves for viruses and serum-replicates with at least one failed barcode:
No description has been provided for this image
Dropping 0 barcode/serum-replicates for failing max_frac_infectivity_at_least=0.0: []

Dropping 142 barcode/serum-replicates for failing goodness_of_fit={'min_R2': 0.5, 'max_RMSD': 0.15}: [('AAAACAGGTCCGGTTT', 'A230212d0_rd512'), ('AAATACCCTTGAGATA', 'A230212d0_rd512'), ('AAGTGGTAGGATAAAA', 'A230212d0_rd512'), ('AATGACAGCTGTCTAG', 'A230212d0_rd512'), ('ACAGTACAGATATGAC', 'A230212d0_rd512'), ('ACCCTTTTAGATATGA', 'A230212d0_rd512'), ('ACGTAAATCCCCACAA', 'A230212d0_rd512'), ('AGATCATAAGCAATAA', 'A230212d0_rd512'), ('AGCAGACACTTTACAT', 'A230212d0_rd512'), ('AGCATGAGCTTGTCAT', 'A230212d0_rd512'), ('AGCTATGCCTAGTGAA', 'A230212d0_rd512'), ('AGGGACTTTATTGTCC', 'A230212d0_rd512'), ('ATAAAGAATCCCTTGA', 'A230212d0_rd512'), ('ATTTATATTGTCGAAC', 'A230212d0_rd512'), ('CAAAAAGCTAATAAGT', 'A230212d0_rd512'), ('CACCCAAACGTTCGCA', 'A230212d0_rd512'), ('CACCTTCATCCTAAAG', 'A230212d0_rd512'), ('CAGTAGCAAAACATGC', 'A230212d0_rd512'), ('CAGTGCCATCCATCCA', 'A230212d0_rd512'), ('CATATTCTAAAATTGA', 'A230212d0_rd512'), ('CATCATTATTACAAAG', 'A230212d0_rd512'), ('CCACAAGTTTGAAAAC', 'A230212d0_rd512'), ('CCACGCACTTAAATAA', 'A230212d0_rd512'), ('CCATATATAAGAAACC', 'A230212d0_rd512'), ('CCCATATACTCACAGA', 'A230212d0_rd512'), ('CCCGCTAACCCTGTCT', 'A230212d0_rd512'), ('CCGATAAGACGTCGCT', 'A230212d0_rd512'), ('CCTATTATAGCTAACA', 'A230212d0_rd512'), ('CGATCTTTACGAAAAA', 'A230212d0_rd512'), ('CGCAAGGGATACTAAC', 'A230212d0_rd512'), ('CGTCAGAAGTTTATAA', 'A230212d0_rd512'), ('CTACACTACATCAAAT', 'A230212d0_rd512'), ('CTACTAGAGCAGCGAG', 'A230212d0_rd512'), ('CTGAAACCTTGTCCTA', 'A230212d0_rd512'), ('CTTACAAAGGTAATTC', 'A230212d0_rd512'), ('CTTGAATACACAAACA', 'A230212d0_rd512'), ('GAAAATCGAGCTTTAA', 'A230212d0_rd512'), ('GAAAGAAAGCTATATG', 'A230212d0_rd512'), ('GACCAAAAAGCAGTAT', 'A230212d0_rd512'), ('GACCAAAGCTGCAGGG', 'A230212d0_rd512'), ('GAGATAGCCCAGAGGT', 'A230212d0_rd512'), ('GCCGTAGCGAAATCTT', 'A230212d0_rd512'), ('GCTTTTGAGAACCATT', 'A230212d0_rd512'), ('GTAGAAACTAGGAGTT', 'A230212d0_rd512'), ('TACCATTTTGGTCCGC', 'A230212d0_rd512'), ('TACTGAGACACTTAAA', 'A230212d0_rd512'), ('TAGATAATAAGATTCA', 'A230212d0_rd512'), ('TATCAATTCGGTATTA', 'A230212d0_rd512'), ('TATCATTTCATCTACA', 'A230212d0_rd512'), ('TCCAAACAGCGTTAAA', 'A230212d0_rd512'), ('TCCGCCACTATAACAT', 'A230212d0_rd512'), ('TCTTAACTACCCGATG', 'A230212d0_rd512'), ('TCTTACATTGAAAGGC', 'A230212d0_rd512'), ('TGATCCGCAAGCTTAG', 'A230212d0_rd512'), ('TGCCGATCCAATTGAT', 'A230212d0_rd512'), ('TTACGACGTCATGTAT', 'A230212d0_rd512'), ('TTACGTCAATGTTTGA', 'A230212d0_rd512'), ('TTAGTCATCTGGGTGC', 'A230212d0_rd512'), ('TTATAATGGCCGGTAT', 'A230212d0_rd512'), ('TTATGATCGAGGTAAA', 'A230212d0_rd512'), ('TTTATGCCGATAGAGA', 'A230212d0_rd512'), ('AAAACAGGTCCGGTTT', 'A230212d28_rd512'), ('AAACTTCGTGGTATAC', 'A230212d28_rd512'), ('AAAGATAAATTCAAAA', 'A230212d28_rd512'), ('AACAAGGCCAACATTT', 'A230212d28_rd512'), ('AACGACAACCATGAAT', 'A230212d28_rd512'), ('AACGACACTTACATCC', 'A230212d28_rd512'), ('AAGAAATTATGGCAGG', 'A230212d28_rd512'), ('AAGCGGTTTAGGTCCA', 'A230212d28_rd512'), ('AAGTGGTAGGATAAAA', 'A230212d28_rd512'), ('AATATACCGGCACTAC', 'A230212d28_rd512'), ('AATCCGATAAGAGCTA', 'A230212d28_rd512'), ('AATCCGGTTAACCCCG', 'A230212d28_rd512'), ('AATCTTTCCAATCTTG', 'A230212d28_rd512'), ('AATGACAGCTGTCTAG', 'A230212d28_rd512'), ('AATGGTCGAGCCATTC', 'A230212d28_rd512'), ('ACAGTACAGATATGAC', 'A230212d28_rd512'), ('ACGGACAACCTATCGC', 'A230212d28_rd512'), ('ACGTAAATCCCCACAA', 'A230212d28_rd512'), ('AGATGGAGGAATAAAC', 'A230212d28_rd512'), ('AGCAGACACTTTACAT', 'A230212d28_rd512'), ('AGCTATGCCTAGTGAA', 'A230212d28_rd512'), ('AGGGACTTTATTGTCC', 'A230212d28_rd512'), ('AGTTATGTAAAACGTG', 'A230212d28_rd512'), ('ATAAAGAATCCCTTGA', 'A230212d28_rd512'), ('ATAATAATCATCAAGA', 'A230212d28_rd512'), ('ATGGTTATCTTACCTT', 'A230212d28_rd512'), ('ATTCAATACGTACTTA', 'A230212d28_rd512'), ('CAAGAAATGTAGTGAA', 'A230212d28_rd512'), ('CAATGGATAATGATAG', 'A230212d28_rd512'), ('CACCACAGTTACTTAA', 'A230212d28_rd512'), ('CACCTTCATCCTAAAG', 'A230212d28_rd512'), ('CAGTAGCAAAACATGC', 'A230212d28_rd512'), ('CATAATGCACAAACGC', 'A230212d28_rd512'), ('CATATTCTAAAATTGA', 'A230212d28_rd512'), ('CATCATTATTACAAAG', 'A230212d28_rd512'), ('CCAATCATGTATCACA', 'A230212d28_rd512'), ('CCACAAGTTTGAAAAC', 'A230212d28_rd512'), ('CCACGTTCATTAGATG', 'A230212d28_rd512'), ('CCAGAGACACGCTAGG', 'A230212d28_rd512'), ('CCATATATAAGAAACC', 'A230212d28_rd512'), ('CCATCACCTTATACAC', 'A230212d28_rd512'), ('CCCATATACTCACAGA', 'A230212d28_rd512'), ('CCCCAGGTATAAAATA', 'A230212d28_rd512'), ('CGATCTTTACGAAAAA', 'A230212d28_rd512'), ('CGCAAGGGATACTAAC', 'A230212d28_rd512'), ('CGCCGAACGGCGGCGC', 'A230212d28_rd512'), ('CGCGAATCACTAAGTA', 'A230212d28_rd512'), ('CTGTGAAAAAAAATAC', 'A230212d28_rd512'), ('GAAAGAAAGCTATATG', 'A230212d28_rd512'), ('GAAGTAACAAACTATG', 'A230212d28_rd512'), ('GACATCAAATAGCAAC', 'A230212d28_rd512'), ('GACCTCCTGGGCACGC', 'A230212d28_rd512'), ('GAGATAGCCCAGAGGT', 'A230212d28_rd512'), ('GAGCCCGAATAGCAAG', 'A230212d28_rd512'), ('GATCTGCTTGGAATGT', 'A230212d28_rd512'), ('GCAACGAGGTGTAACC', 'A230212d28_rd512'), ('GCCCATTGAACGCAGC', 'A230212d28_rd512'), ('GGCAATAAGTTAAATG', 'A230212d28_rd512'), ('GTTATTATGACTTCAT', 'A230212d28_rd512'), ('TAAACTGTAACTTACA', 'A230212d28_rd512'), ('TACCAATGTCATTTGA', 'A230212d28_rd512'), ('TACGAAAATCAAGAGC', 'A230212d28_rd512'), ('TACGACGGAAACAGAA', 'A230212d28_rd512'), ('TAGATAATAAGATTCA', 'A230212d28_rd512'), ('TAGCTGGGCAAAGGCT', 'A230212d28_rd512'), ('TATCATTTCATCTACA', 'A230212d28_rd512'), ('TATCGCAATATGATAA', 'A230212d28_rd512'), ('TATTATCTAAACGGCG', 'A230212d28_rd512'), ('TCAACCCTTCGATGTA', 'A230212d28_rd512'), ('TCCAAACAGCGTTAAA', 'A230212d28_rd512'), ('TCGCGGTAGATTTGCG', 'A230212d28_rd512'), ('TGAATTGCGTGATGGG', 'A230212d28_rd512'), ('TGATCCGCAAGCTTAG', 'A230212d28_rd512'), ('TGATTCGTCAATTCAT', 'A230212d28_rd512'), ('TGTAGTATAAGAATAA', 'A230212d28_rd512'), ('TTACGTCAATGTTTGA', 'A230212d28_rd512'), ('TTAGCAGTTAACGTAT', 'A230212d28_rd512'), ('TTAGTCATCTGGGTGC', 'A230212d28_rd512'), ('TTATAATGGCCGGTAT', 'A230212d28_rd512'), ('TTGCAATTGAAACATA', 'A230212d28_rd512'), ('TTTATGCCGATAGAGA', 'A230212d28_rd512')]

Fit neutralization curves after applying QC¶

No we re-fit curves after applying all the QC:

In [20]:
fits_qc = neutcurve.CurveFits(
    frac_infectivity.rename(
        columns={
            "frac_infectivity_ceiling": "fraction infectivity",
            "concentration": "serum concentration",
        }
    ),
    conc_col="serum concentration",
    fracinf_col="fraction infectivity",
    virus_col="strain",
    serum_col="serum",
    replicate_col="plate_barcode",
    fixtop=curvefit_params["fixtop"],
    fixbottom=curvefit_params["fixbottom"],
    fixslope=curvefit_params["fixslope"],
)

fit_params_qc = fits_qc.fitParams(average_only=False, no_average=True)
assert len(fit_params_qc) <= len(
    fits_noqc.fitParams(average_only=False, no_average=True)
)

print(f"Assigning fits for this plate to {group}")
fit_params_qc.insert(0, "group", group)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
/fh/fast/bloom_j/computational_notebooks/ckikawa/2024/flu_seqneut_H3N2_2023-2024/.snakemake/conda/3d7bcea0b75814e39f27531956478cb3_/lib/python3.12/site-packages/neutcurve/hillcurve.py:1177: RuntimeWarning: invalid value encountered in power
  return b + (t - b) / (1 + (c / m) ** s)
Assigning fits for this plate to pilot

Plot all the curves that passed QC:

In [21]:
if fits_qc.sera:
    _ = fits_qc.plotReplicates(
        attempt_shared_legend=False,
        legendfontsize=8,
        titlesize=10,
        ticksize=10,
        ncol=6,
        draw_in_bounds=True,
    )
else:
    print("No sera passed QC.")
No description has been provided for this image

Save results to files¶

In [22]:
print(f"Writing fraction infectivities to {frac_infectivity_csv}")
(
    frac_infectivity[
        [
            "serum",
            "strain",
            "plate_barcode",
            "dilution_factor",
            "frac_infectivity_raw",
            "frac_infectivity_ceiling",
        ]
    ]
    .sort_values(["serum", "plate_barcode", "dilution_factor"])
    .to_csv(frac_infectivity_csv, index=False, float_format="%.4g")
)

print(f"\nWriting fit parameters to {fits_csv}")
(
    fit_params_qc.drop(columns=["nreplicates", "ic50_str"]).to_csv(
        fits_csv, index=False, float_format="%.4g"
    )
)

print(f"\nPickling neutcurve.CurveFits object for these data to {fits_pickle}")
with open(fits_pickle, "wb") as f:
    pickle.dump(fits_qc, f)

print(f"\nWriting QC drops to {qc_drops_yaml}")


def tup_to_str(x):
    return " ".join(x) if isinstance(x, tuple) else x


qc_drops_for_yaml = {
    key: {tup_to_str(key2): val2 for key2, val2 in val.items()}
    for key, val in qc_drops.items()
}
with open(qc_drops_yaml, "w") as f:
    yaml.YAML(typ="rt").dump(qc_drops_for_yaml, f)
print("\nHere are the QC drops:\n***************************")
yaml.YAML(typ="rt").dump(qc_drops_for_yaml, sys.stdout)
Writing fraction infectivities to results/plates/plate7/frac_infectivity.csv

Writing fit parameters to results/plates/plate7/curvefits.csv

Pickling neutcurve.CurveFits object for these data to results/plates/plate7/curvefits.pickle

Writing QC drops to results/plates/plate7/qc_drops.yml

Here are the QC drops:
***************************
wells:
  D7: avg_barcode_counts_per_well
  H7: avg_barcode_counts_per_well
barcodes:
  AAAGTAGCAGAGGATT: min_neut_standard_frac_per_well
  AAATTCACAATATCCA: min_neut_standard_frac_per_well
  AACAATTAATTTTTCA: min_neut_standard_frac_per_well
  AAGTTGTACTTAAGGC: min_neut_standard_frac_per_well
  AATAGGCCCAAATCCA: min_neut_standard_frac_per_well
  AATTAATGGTAATAAA: min_neut_standard_frac_per_well
  ACAAAGATAAAAATTT: min_neut_standard_frac_per_well
  AGAAAAACGACATCAT: min_neut_standard_frac_per_well
  AGACCATCGCACCCAA: min_neut_standard_frac_per_well
  AGTGCTATAAAAATCA: min_neut_standard_frac_per_well
  ATAACGTTTGTGCAAA: min_neut_standard_frac_per_well
  ATCGATTCGATTGACG: min_neut_standard_frac_per_well
  ATGCGTCTAAACATAG: min_neut_standard_frac_per_well
  CAAAAGCAGCACGATA: min_neut_standard_frac_per_well
  CAAGACAAGCCCTATA: min_neut_standard_frac_per_well
  CAGATAGTGATGAACA: min_neut_standard_frac_per_well
  CATAAAAGACTGTATA: min_neut_standard_frac_per_well
  CCAATCCCAGCCTTTA: min_neut_standard_frac_per_well
  CCCTCCTCAAGGGTAA: min_neut_standard_frac_per_well
  CCTATAAGGCCTTACG: min_neut_standard_frac_per_well
  CGTACGTATGTCCCAG: min_neut_standard_frac_per_well
  CGTCCCTGGCGTGTCG: min_neut_standard_frac_per_well
  CGTTAACGGCCTATCC: min_neut_standard_frac_per_well
  CTCCAATAGGAGACGA: min_neut_standard_frac_per_well
  GCTGAAGACAGTATTA: min_neut_standard_frac_per_well
  GTAATTCGCATGCGGA: min_neut_standard_frac_per_well
  TATATGGAATACTAAA: min_neut_standard_frac_per_well
  TCGTCCTAGAACCTAA: min_neut_standard_frac_per_well
  TCTCCGATAGCCCTAC: min_neut_standard_frac_per_well
  TGGCTAGCGCACACCA: min_neut_standard_frac_per_well
  TGTTGTAATCTGAATA: min_neut_standard_frac_per_well
  TTACATTTTTAGAATT: min_neut_standard_frac_per_well
  TTATGTTTTAATGGTA: min_neut_standard_frac_per_well
  TTGCTAGTCTACCTGA: min_neut_standard_frac_per_well
barcode_wells:
  AATCCGGTTAACCCCG D12: min_no_serum_count_per_viral_barcode_well
  TTTCATATAATTTGAG D12: min_no_serum_count_per_viral_barcode_well
  AAAACAGGTCCGGTTT D12: min_no_serum_count_per_viral_barcode_well
  GATCTGCTTGGAATGT D12: min_no_serum_count_per_viral_barcode_well
  CCACAAGTTTGAAAAC D12: min_no_serum_count_per_viral_barcode_well
  CGGGAATCTCCCATAC D12: min_no_serum_count_per_viral_barcode_well
  ATTCAATACGTACTTA D12: min_no_serum_count_per_viral_barcode_well
  CATAATGCACAAACGC D12: min_no_serum_count_per_viral_barcode_well
  CCACGCACTTAAATAA D12: min_no_serum_count_per_viral_barcode_well
  CCATCACCTTATACAC D12: min_no_serum_count_per_viral_barcode_well
  CACCGACCAACTCTCT D12: min_no_serum_count_per_viral_barcode_well
  TCCCGAACTGAACGCG D12: min_no_serum_count_per_viral_barcode_well
  TTATAATGGCCGGTAT D12: min_no_serum_count_per_viral_barcode_well
  AACGACACTTACATCC D12: min_no_serum_count_per_viral_barcode_well
  AGACTGTACGCGACAG D12: min_no_serum_count_per_viral_barcode_well
  GAAAGAAAGCTATATG D12: min_no_serum_count_per_viral_barcode_well
  TACTGAGACACTTAAA D12: min_no_serum_count_per_viral_barcode_well
  CGCGAACAACAGGGGA D12: min_no_serum_count_per_viral_barcode_well
  GTTTTTCACTGAGTAG D12: min_no_serum_count_per_viral_barcode_well
  AAAGACCTTTAACTCT D12: min_no_serum_count_per_viral_barcode_well
  AAGCTAATCGTAGTCC D12: min_no_serum_count_per_viral_barcode_well
  AATGACAGCTGTCTAG D12: min_no_serum_count_per_viral_barcode_well
  ACGGACAACCTATCGC D12: min_no_serum_count_per_viral_barcode_well
  CCGGTTTTCGGGACCT D12: min_no_serum_count_per_viral_barcode_well
  CTACTAGAGCAGCGAG D12: min_no_serum_count_per_viral_barcode_well
  CTCATTACAGAAATTG D12: min_no_serum_count_per_viral_barcode_well
  CTTCATCTCATTTAAA D12: min_no_serum_count_per_viral_barcode_well
  GACAGAAACAAAATTA D12: min_no_serum_count_per_viral_barcode_well
  GTAGAAACTAGGAGTT D12: min_no_serum_count_per_viral_barcode_well
  TAGTTGCCCCGACCTG D12: min_no_serum_count_per_viral_barcode_well
  AGTTATGTAAAACGTG H12: min_no_serum_count_per_viral_barcode_well
  AAGTATTGCTACACAT H12: min_no_serum_count_per_viral_barcode_well
  AATCCGATAAGAGCTA H12: min_no_serum_count_per_viral_barcode_well
  CGCAGTACACAACAAG H12: min_no_serum_count_per_viral_barcode_well
  CCCGCTAACCCTGTCT H12: min_no_serum_count_per_viral_barcode_well
  TTAGCTACTAACCCGT H12: min_no_serum_count_per_viral_barcode_well
  ACGTAAATCCCCACAA H12: min_no_serum_count_per_viral_barcode_well
  CACGTTAGTGAGACTT H12: min_no_serum_count_per_viral_barcode_well
  CAGTAGCAAAACATGC H12: min_no_serum_count_per_viral_barcode_well
  ACTATACATAGAAGAA H12: min_no_serum_count_per_viral_barcode_well
  CCGCAATGACAATTTG H12: min_no_serum_count_per_viral_barcode_well
  GACCTCCTGGGCACGC H12: min_no_serum_count_per_viral_barcode_well
  TGCCGATCCAATTGAT H12: min_no_serum_count_per_viral_barcode_well
  ACGCAAATAGACCGAA H12: min_no_serum_count_per_viral_barcode_well
  AGGTGCGAGCCATCAG H12: min_no_serum_count_per_viral_barcode_well
  TCCGCCACTATAACAT H12: min_no_serum_count_per_viral_barcode_well
  CCAGAGACACGCTAGG H12: min_no_serum_count_per_viral_barcode_well
  CACCCAAACGTTCGCA H12: min_no_serum_count_per_viral_barcode_well
  CAATTCGCCGTTCCCC H12: min_no_serum_count_per_viral_barcode_well
  CTACACTACATCAAAT H12: min_no_serum_count_per_viral_barcode_well
  AATTACGCATAGGCCA H12: min_no_serum_count_per_viral_barcode_well
  CCGCTATCATTAACCC H12: min_no_serum_count_per_viral_barcode_well
  CTAAGGGCCTGTTCTT H12: min_no_serum_count_per_viral_barcode_well
  AATGGTCGAGCCATTC H12: min_no_serum_count_per_viral_barcode_well
  ATAGAAAATTATCCGC H12: min_no_serum_count_per_viral_barcode_well
  CAGCCGCTAAAATGAT H12: min_no_serum_count_per_viral_barcode_well
  CCTATTATAGCTAACA H12: min_no_serum_count_per_viral_barcode_well
  CGATCTTTACGAAAAA H12: min_no_serum_count_per_viral_barcode_well
  TAAACTGTAACTTACA H12: min_no_serum_count_per_viral_barcode_well
  TGATCCGCAAGCTTAG H12: min_no_serum_count_per_viral_barcode_well
  TAGCTGGGCAAAGGCT D2: max_frac_infectivity_per_viral_barcode_well
  GACCAAAGCTGCAGGG D2: max_frac_infectivity_per_viral_barcode_well
  TAGTTGCCCCGACCTG D2: max_frac_infectivity_per_viral_barcode_well
  TAGATAATAAGATTCA D3: max_frac_infectivity_per_viral_barcode_well
  GACAGAAACAAAATTA D4: max_frac_infectivity_per_viral_barcode_well
  AAATACCCTTGAGATA D4: max_frac_infectivity_per_viral_barcode_well
  ATCGTCCCGGACATTT D4: max_frac_infectivity_per_viral_barcode_well
  ATGGTTATCTTACCTT D4: max_frac_infectivity_per_viral_barcode_well
  TCTTGAATTTCATGGA D4: max_frac_infectivity_per_viral_barcode_well
  TATTATCTAAACGGCG D5: max_frac_infectivity_per_viral_barcode_well
  GTTTTTCACTGAGTAG D5: max_frac_infectivity_per_viral_barcode_well
  ACCCTTTTAGATATGA D5: max_frac_infectivity_per_viral_barcode_well
  ACTATACATAGAAGAA D5: max_frac_infectivity_per_viral_barcode_well
  GCCCATTGAACGCAGC D5: max_frac_infectivity_per_viral_barcode_well
  CTATCTTAATCTACAG D5: max_frac_infectivity_per_viral_barcode_well
  TCAAACTATGATATTC D5: max_frac_infectivity_per_viral_barcode_well
  ACCGTTTTTCTACCAG D5: max_frac_infectivity_per_viral_barcode_well
  CCCGCTAACCCTGTCT D5: max_frac_infectivity_per_viral_barcode_well
  CGCCGAACGGCGGCGC D5: max_frac_infectivity_per_viral_barcode_well
  ATCGTCCCGGACATTT D5: max_frac_infectivity_per_viral_barcode_well
  GAGATAGCCCAGAGGT D6: max_frac_infectivity_per_viral_barcode_well
  AACAAGGCCAACATTT D6: max_frac_infectivity_per_viral_barcode_well
  CCGCTATCATTAACCC D6: max_frac_infectivity_per_viral_barcode_well
  TACCATTTTGGTCCGC D6: max_frac_infectivity_per_viral_barcode_well
  CGCAAGGGATACTAAC D6: max_frac_infectivity_per_viral_barcode_well
  ATAAAGAATCCCTTGA D6: max_frac_infectivity_per_viral_barcode_well
  CCACAAGTTTGAAAAC D6: max_frac_infectivity_per_viral_barcode_well
  AAACTTCGTGGTATAC D6: max_frac_infectivity_per_viral_barcode_well
  CCATCACCTTATACAC D6: max_frac_infectivity_per_viral_barcode_well
  GATTCACGGCCCACAA D6: max_frac_infectivity_per_viral_barcode_well
  TGATTCGTCAATTCAT D6: max_frac_infectivity_per_viral_barcode_well
  TTTCATATAATTTGAG D6: max_frac_infectivity_per_viral_barcode_well
  TCTTGAATTTCATGGA D6: max_frac_infectivity_per_viral_barcode_well
  CTACACTACATCAAAT D6: max_frac_infectivity_per_viral_barcode_well
  GCAACGAGGTGTAACC D8: max_frac_infectivity_per_viral_barcode_well
  AACGACACTTACATCC D8: max_frac_infectivity_per_viral_barcode_well
  TTTCATATAATTTGAG D8: max_frac_infectivity_per_viral_barcode_well
  AAACTTCGTGGTATAC D8: max_frac_infectivity_per_viral_barcode_well
  ACGTAAATCCCCACAA D8: max_frac_infectivity_per_viral_barcode_well
  CCACAAGTTTGAAAAC D8: max_frac_infectivity_per_viral_barcode_well
  TCAACCCTTCGATGTA D8: max_frac_infectivity_per_viral_barcode_well
  GAAGTAACAAACTATG D8: max_frac_infectivity_per_viral_barcode_well
  GATTCACGGCCCACAA D8: max_frac_infectivity_per_viral_barcode_well
  TTGACTCACCGAATAA D8: max_frac_infectivity_per_viral_barcode_well
  CCCATATACTCACAGA D8: max_frac_infectivity_per_viral_barcode_well
  CCAATCATGTATCACA D8: max_frac_infectivity_per_viral_barcode_well
  AAGCGGTTTAGGTCCA D8: max_frac_infectivity_per_viral_barcode_well
  CCACAAGTTTGAAAAC D9: max_frac_infectivity_per_viral_barcode_well
  TCTTAACTACCCGATG D9: max_frac_infectivity_per_viral_barcode_well
  CCGATAAGACGTCGCT D9: max_frac_infectivity_per_viral_barcode_well
  TCTTGAATTTCATGGA D9: max_frac_infectivity_per_viral_barcode_well
  TCAACCCTTCGATGTA D9: max_frac_infectivity_per_viral_barcode_well
  AGTTATGTAAAACGTG D9: max_frac_infectivity_per_viral_barcode_well
  CTATCTTAATCTACAG D9: max_frac_infectivity_per_viral_barcode_well
  GCATTATAATCTTGTG D9: max_frac_infectivity_per_viral_barcode_well
  ATGGTTATCTTACCTT D9: max_frac_infectivity_per_viral_barcode_well
  TGATTCGTCAATTCAT D9: max_frac_infectivity_per_viral_barcode_well
  CTACACTACATCAAAT D9: max_frac_infectivity_per_viral_barcode_well
  GAAGTAACAAACTATG D9: max_frac_infectivity_per_viral_barcode_well
  CTTCATCTCATTTAAA D9: max_frac_infectivity_per_viral_barcode_well
  AGTTATGTAAAACGTG D10: max_frac_infectivity_per_viral_barcode_well
  CTTGAATACACAAACA D10: max_frac_infectivity_per_viral_barcode_well
  AATCTTTCCAATCTTG D10: max_frac_infectivity_per_viral_barcode_well
  CCATCACCTTATACAC D10: max_frac_infectivity_per_viral_barcode_well
  GGGTGCAATGAATCCA D10: max_frac_infectivity_per_viral_barcode_well
  TCTTGAATTTCATGGA D10: max_frac_infectivity_per_viral_barcode_well
  GACAGAAACAAAATTA D10: max_frac_infectivity_per_viral_barcode_well
  CTTACAAAGGTAATTC D10: max_frac_infectivity_per_viral_barcode_well
  TAGATAATAAGATTCA D10: max_frac_infectivity_per_viral_barcode_well
  CCGATAAGACGTCGCT D10: max_frac_infectivity_per_viral_barcode_well
  AAGCGGTTTAGGTCCA D10: max_frac_infectivity_per_viral_barcode_well
  CTATCTTAATCTACAG D10: max_frac_infectivity_per_viral_barcode_well
  CGCGAATCACTAAGTA D10: max_frac_infectivity_per_viral_barcode_well
  CTGTGAAAAAAAATAC D10: max_frac_infectivity_per_viral_barcode_well
  TGATTCGTCAATTCAT D10: max_frac_infectivity_per_viral_barcode_well
  CCAATCATGTATCACA D10: max_frac_infectivity_per_viral_barcode_well
  TTGACTCACCGAATAA D10: max_frac_infectivity_per_viral_barcode_well
  AACGACACTTACATCC D10: max_frac_infectivity_per_viral_barcode_well
  GAAAGAAAGCTATATG D10: max_frac_infectivity_per_viral_barcode_well
  CATAATGCACAAACGC D10: max_frac_infectivity_per_viral_barcode_well
  TTCATCAAGTTGGTGC D11: max_frac_infectivity_per_viral_barcode_well
  TCTTGAATTTCATGGA D11: max_frac_infectivity_per_viral_barcode_well
  CAAAAAGCTAATAAGT D11: max_frac_infectivity_per_viral_barcode_well
  CTTCATCTCATTTAAA D11: max_frac_infectivity_per_viral_barcode_well
  CACCACAGTTACTTAA D11: max_frac_infectivity_per_viral_barcode_well
  CCGATAAGACGTCGCT D11: max_frac_infectivity_per_viral_barcode_well
  CCACGCACTTAAATAA D11: max_frac_infectivity_per_viral_barcode_well
  TAGTTGCCCCGACCTG D11: max_frac_infectivity_per_viral_barcode_well
  AAATACCCTTGAGATA D11: max_frac_infectivity_per_viral_barcode_well
  AGTTATGTAAAACGTG D11: max_frac_infectivity_per_viral_barcode_well
  GCATTATAATCTTGTG D11: max_frac_infectivity_per_viral_barcode_well
  ATGGTTATCTTACCTT D11: max_frac_infectivity_per_viral_barcode_well
  GGCTATATATCTGTTT D11: max_frac_infectivity_per_viral_barcode_well
  CGCCGAACGGCGGCGC D11: max_frac_infectivity_per_viral_barcode_well
  GATTCACGGCCCACAA D11: max_frac_infectivity_per_viral_barcode_well
  CGCAAGGGATACTAAC H2: max_frac_infectivity_per_viral_barcode_well
  TGATTCGTCAATTCAT H4: max_frac_infectivity_per_viral_barcode_well
  CTTGAATACACAAACA H4: max_frac_infectivity_per_viral_barcode_well
  CTATCTTAATCTACAG H4: max_frac_infectivity_per_viral_barcode_well
  CACCACAGTTACTTAA H4: max_frac_infectivity_per_viral_barcode_well
  GAAAGAAAGCTATATG H4: max_frac_infectivity_per_viral_barcode_well
  CTGAAACCTTGTCCTA H5: max_frac_infectivity_per_viral_barcode_well
  TACCATTTTGGTCCGC H5: max_frac_infectivity_per_viral_barcode_well
  TGAGATCAGCCGGGTG H5: max_frac_infectivity_per_viral_barcode_well
  GGTTGCGTAGTTAATC H5: max_frac_infectivity_per_viral_barcode_well
  CTTACAAAGGTAATTC H5: max_frac_infectivity_per_viral_barcode_well
  CCCGCTAACCCTGTCT H5: max_frac_infectivity_per_viral_barcode_well
  CTGTGAAAAAAAATAC H5: max_frac_infectivity_per_viral_barcode_well
  GCTAATTCCAAAAGCG H5: max_frac_infectivity_per_viral_barcode_well
  TGTAGTATAAGAATAA H5: max_frac_infectivity_per_viral_barcode_well
  TCAACCCTTCGATGTA H5: max_frac_infectivity_per_viral_barcode_well
  AGTTATGTAAAACGTG H5: max_frac_infectivity_per_viral_barcode_well
  ACTATACATAGAAGAA H5: max_frac_infectivity_per_viral_barcode_well
  TCTTGAATTTCATGGA H5: max_frac_infectivity_per_viral_barcode_well
  TATTATCTAAACGGCG H6: max_frac_infectivity_per_viral_barcode_well
  GTTTTTCACTGAGTAG H6: max_frac_infectivity_per_viral_barcode_well
  AAGTGGTAGGATAAAA H6: max_frac_infectivity_per_viral_barcode_well
  TAGTTGCCCCGACCTG H6: max_frac_infectivity_per_viral_barcode_well
  CCACGCACTTAAATAA H8: max_frac_infectivity_per_viral_barcode_well
  GCCCATTGAACGCAGC H8: max_frac_infectivity_per_viral_barcode_well
  AAACTTCGTGGTATAC H8: max_frac_infectivity_per_viral_barcode_well
  AGATCATAAGCAATAA H8: max_frac_infectivity_per_viral_barcode_well
  TCTTGAATTTCATGGA H8: max_frac_infectivity_per_viral_barcode_well
  TAGATAATAAGATTCA H8: max_frac_infectivity_per_viral_barcode_well
  TAAAAGAATGATGGTC H8: max_frac_infectivity_per_viral_barcode_well
  CTTACAAAGGTAATTC H8: max_frac_infectivity_per_viral_barcode_well
  CACCACAGTTACTTAA H8: max_frac_infectivity_per_viral_barcode_well
  GAAGTAACAAACTATG H8: max_frac_infectivity_per_viral_barcode_well
  AACAAGGCCAACATTT H8: max_frac_infectivity_per_viral_barcode_well
  AAGCGGTTTAGGTCCA H8: max_frac_infectivity_per_viral_barcode_well
  TGACAAACACCTGAGG H8: max_frac_infectivity_per_viral_barcode_well
  ATAAAGAATCCCTTGA H8: max_frac_infectivity_per_viral_barcode_well
  GCTAATTCCAAAAGCG H9: max_frac_infectivity_per_viral_barcode_well
  GGGTGCAATGAATCCA H9: max_frac_infectivity_per_viral_barcode_well
  CGCGAATCACTAAGTA H9: max_frac_infectivity_per_viral_barcode_well
  TCCTTTAACTAATCGA H9: max_frac_infectivity_per_viral_barcode_well
  CTTACAAAGGTAATTC H9: max_frac_infectivity_per_viral_barcode_well
  TCAACCCTTCGATGTA H9: max_frac_infectivity_per_viral_barcode_well
  CAATGGATAATGATAG H9: max_frac_infectivity_per_viral_barcode_well
  AAACTTCGTGGTATAC H9: max_frac_infectivity_per_viral_barcode_well
  TAGATAATAAGATTCA H9: max_frac_infectivity_per_viral_barcode_well
  CCACAAGTTTGAAAAC H9: max_frac_infectivity_per_viral_barcode_well
  CACCTTCATCCTAAAG H9: max_frac_infectivity_per_viral_barcode_well
  AAATACCCTTGAGATA H9: max_frac_infectivity_per_viral_barcode_well
  TTTCATATAATTTGAG H9: max_frac_infectivity_per_viral_barcode_well
  TATCAATTCGGTATTA H9: max_frac_infectivity_per_viral_barcode_well
  TTAGCTACTAACCCGT H9: max_frac_infectivity_per_viral_barcode_well
  TGTAGTATAAGAATAA H9: max_frac_infectivity_per_viral_barcode_well
  CGCCGAACGGCGGCGC H9: max_frac_infectivity_per_viral_barcode_well
  TCTTGAATTTCATGGA H9: max_frac_infectivity_per_viral_barcode_well
  CTACACTACATCAAAT H9: max_frac_infectivity_per_viral_barcode_well
  GAAAGAAAGCTATATG H9: max_frac_infectivity_per_viral_barcode_well
  AAGTGGTAGGATAAAA H10: max_frac_infectivity_per_viral_barcode_well
  TACCATTTTGGTCCGC H10: max_frac_infectivity_per_viral_barcode_well
  GCTAATTCCAAAAGCG H10: max_frac_infectivity_per_viral_barcode_well
  TTGACTCACCGAATAA H10: max_frac_infectivity_per_viral_barcode_well
  CGCAAGGGATACTAAC H10: max_frac_infectivity_per_viral_barcode_well
  ACTATACATAGAAGAA H10: max_frac_infectivity_per_viral_barcode_well
  CTACACTACATCAAAT H10: max_frac_infectivity_per_viral_barcode_well
  TTTATGCCGATAGAGA H10: max_frac_infectivity_per_viral_barcode_well
  CAGTAGCAAAACATGC H10: max_frac_infectivity_per_viral_barcode_well
  CCACGCACTTAAATAA H10: max_frac_infectivity_per_viral_barcode_well
  CGCGAACAACAGGGGA H10: max_frac_infectivity_per_viral_barcode_well
  TCAACCCTTCGATGTA H10: max_frac_infectivity_per_viral_barcode_well
  AGTTATGTAAAACGTG H10: max_frac_infectivity_per_viral_barcode_well
  TAGTTGCCCCGACCTG H10: max_frac_infectivity_per_viral_barcode_well
  GTTTTTCACTGAGTAG H10: max_frac_infectivity_per_viral_barcode_well
  GCATTATAATCTTGTG H10: max_frac_infectivity_per_viral_barcode_well
  CGGCTAAAGTCTATAG H10: max_frac_infectivity_per_viral_barcode_well
  TTTCATATAATTTGAG H10: max_frac_infectivity_per_viral_barcode_well
  CCCATATACTCACAGA H10: max_frac_infectivity_per_viral_barcode_well
  GATTCACGGCCCACAA H10: max_frac_infectivity_per_viral_barcode_well
  GCTAATTCCAAAAGCG H11: max_frac_infectivity_per_viral_barcode_well
  GCAACGAGGTGTAACC H11: max_frac_infectivity_per_viral_barcode_well
  GACCTCCTGGGCACGC H11: max_frac_infectivity_per_viral_barcode_well
  CGTATAACTGACGATT H11: max_frac_infectivity_per_viral_barcode_well
  TAGTTGCCCCGACCTG H11: max_frac_infectivity_per_viral_barcode_well
  CCGCTATCATTAACCC H11: max_frac_infectivity_per_viral_barcode_well
  CGTACAGTGTAATCGA H11: max_frac_infectivity_per_viral_barcode_well
  GCTTTTGAGAACCATT H11: max_frac_infectivity_per_viral_barcode_well
  ATGGTTATCTTACCTT H11: max_frac_infectivity_per_viral_barcode_well
  GCCGTAGCGAAATCTT H11: max_frac_infectivity_per_viral_barcode_well
  AAAGATAAATTCAAAA H11: max_frac_infectivity_per_viral_barcode_well
  GCATTATAATCTTGTG H11: max_frac_infectivity_per_viral_barcode_well
  TACTGAGACACTTAAA H11: max_frac_infectivity_per_viral_barcode_well
  TAAAAGAATGATGGTC H11: max_frac_infectivity_per_viral_barcode_well
  CGCGAATCACTAAGTA H11: max_frac_infectivity_per_viral_barcode_well
  ACCGTTTTTCTACCAG H11: max_frac_infectivity_per_viral_barcode_well
  GTAGAAACTAGGAGTT H11: max_frac_infectivity_per_viral_barcode_well
  CGCGAACAACAGGGGA H11: max_frac_infectivity_per_viral_barcode_well
  CCAATCATGTATCACA H11: max_frac_infectivity_per_viral_barcode_well
  CATAATGCACAAACGC H11: max_frac_infectivity_per_viral_barcode_well
  CCGCAATGACAATTTG H11: max_frac_infectivity_per_viral_barcode_well
  TCTTGAATTTCATGGA H11: max_frac_infectivity_per_viral_barcode_well
  AAGCGGTTTAGGTCCA H11: max_frac_infectivity_per_viral_barcode_well
barcode_serum_replicates:
  TCTTGAATTTCATGGA A230212d0_rd512: min_dilutions_per_barcode_serum_replicate
  AAAACAGGTCCGGTTT A230212d0_rd512: goodness_of_fit
  AAATACCCTTGAGATA A230212d0_rd512: goodness_of_fit
  AAGTGGTAGGATAAAA A230212d0_rd512: goodness_of_fit
  AATGACAGCTGTCTAG A230212d0_rd512: goodness_of_fit
  ACAGTACAGATATGAC A230212d0_rd512: goodness_of_fit
  ACCCTTTTAGATATGA A230212d0_rd512: goodness_of_fit
  ACGTAAATCCCCACAA A230212d0_rd512: goodness_of_fit
  AGATCATAAGCAATAA A230212d0_rd512: goodness_of_fit
  AGCAGACACTTTACAT A230212d0_rd512: goodness_of_fit
  AGCATGAGCTTGTCAT A230212d0_rd512: goodness_of_fit
  AGCTATGCCTAGTGAA A230212d0_rd512: goodness_of_fit
  AGGGACTTTATTGTCC A230212d0_rd512: goodness_of_fit
  ATAAAGAATCCCTTGA A230212d0_rd512: goodness_of_fit
  ATTTATATTGTCGAAC A230212d0_rd512: goodness_of_fit
  CAAAAAGCTAATAAGT A230212d0_rd512: goodness_of_fit
  CACCCAAACGTTCGCA A230212d0_rd512: goodness_of_fit
  CACCTTCATCCTAAAG A230212d0_rd512: goodness_of_fit
  CAGTAGCAAAACATGC A230212d0_rd512: goodness_of_fit
  CAGTGCCATCCATCCA A230212d0_rd512: goodness_of_fit
  CATATTCTAAAATTGA A230212d0_rd512: goodness_of_fit
  CATCATTATTACAAAG A230212d0_rd512: goodness_of_fit
  CCACAAGTTTGAAAAC A230212d0_rd512: goodness_of_fit
  CCACGCACTTAAATAA A230212d0_rd512: goodness_of_fit
  CCATATATAAGAAACC A230212d0_rd512: goodness_of_fit
  CCCATATACTCACAGA A230212d0_rd512: goodness_of_fit
  CCCGCTAACCCTGTCT A230212d0_rd512: goodness_of_fit
  CCGATAAGACGTCGCT A230212d0_rd512: goodness_of_fit
  CCTATTATAGCTAACA A230212d0_rd512: goodness_of_fit
  CGATCTTTACGAAAAA A230212d0_rd512: goodness_of_fit
  CGCAAGGGATACTAAC A230212d0_rd512: goodness_of_fit
  CGTCAGAAGTTTATAA A230212d0_rd512: goodness_of_fit
  CTACACTACATCAAAT A230212d0_rd512: goodness_of_fit
  CTACTAGAGCAGCGAG A230212d0_rd512: goodness_of_fit
  CTGAAACCTTGTCCTA A230212d0_rd512: goodness_of_fit
  CTTACAAAGGTAATTC A230212d0_rd512: goodness_of_fit
  CTTGAATACACAAACA A230212d0_rd512: goodness_of_fit
  GAAAATCGAGCTTTAA A230212d0_rd512: goodness_of_fit
  GAAAGAAAGCTATATG A230212d0_rd512: goodness_of_fit
  GACCAAAAAGCAGTAT A230212d0_rd512: goodness_of_fit
  GACCAAAGCTGCAGGG A230212d0_rd512: goodness_of_fit
  GAGATAGCCCAGAGGT A230212d0_rd512: goodness_of_fit
  GCCGTAGCGAAATCTT A230212d0_rd512: goodness_of_fit
  GCTTTTGAGAACCATT A230212d0_rd512: goodness_of_fit
  GTAGAAACTAGGAGTT A230212d0_rd512: goodness_of_fit
  TACCATTTTGGTCCGC A230212d0_rd512: goodness_of_fit
  TACTGAGACACTTAAA A230212d0_rd512: goodness_of_fit
  TAGATAATAAGATTCA A230212d0_rd512: goodness_of_fit
  TATCAATTCGGTATTA A230212d0_rd512: goodness_of_fit
  TATCATTTCATCTACA A230212d0_rd512: goodness_of_fit
  TCCAAACAGCGTTAAA A230212d0_rd512: goodness_of_fit
  TCCGCCACTATAACAT A230212d0_rd512: goodness_of_fit
  TCTTAACTACCCGATG A230212d0_rd512: goodness_of_fit
  TCTTACATTGAAAGGC A230212d0_rd512: goodness_of_fit
  TGATCCGCAAGCTTAG A230212d0_rd512: goodness_of_fit
  TGCCGATCCAATTGAT A230212d0_rd512: goodness_of_fit
  TTACGACGTCATGTAT A230212d0_rd512: goodness_of_fit
  TTACGTCAATGTTTGA A230212d0_rd512: goodness_of_fit
  TTAGTCATCTGGGTGC A230212d0_rd512: goodness_of_fit
  TTATAATGGCCGGTAT A230212d0_rd512: goodness_of_fit
  TTATGATCGAGGTAAA A230212d0_rd512: goodness_of_fit
  TTTATGCCGATAGAGA A230212d0_rd512: goodness_of_fit
  AAAACAGGTCCGGTTT A230212d28_rd512: goodness_of_fit
  AAACTTCGTGGTATAC A230212d28_rd512: goodness_of_fit
  AAAGATAAATTCAAAA A230212d28_rd512: goodness_of_fit
  AACAAGGCCAACATTT A230212d28_rd512: goodness_of_fit
  AACGACAACCATGAAT A230212d28_rd512: goodness_of_fit
  AACGACACTTACATCC A230212d28_rd512: goodness_of_fit
  AAGAAATTATGGCAGG A230212d28_rd512: goodness_of_fit
  AAGCGGTTTAGGTCCA A230212d28_rd512: goodness_of_fit
  AAGTGGTAGGATAAAA A230212d28_rd512: goodness_of_fit
  AATATACCGGCACTAC A230212d28_rd512: goodness_of_fit
  AATCCGATAAGAGCTA A230212d28_rd512: goodness_of_fit
  AATCCGGTTAACCCCG A230212d28_rd512: goodness_of_fit
  AATCTTTCCAATCTTG A230212d28_rd512: goodness_of_fit
  AATGACAGCTGTCTAG A230212d28_rd512: goodness_of_fit
  AATGGTCGAGCCATTC A230212d28_rd512: goodness_of_fit
  ACAGTACAGATATGAC A230212d28_rd512: goodness_of_fit
  ACGGACAACCTATCGC A230212d28_rd512: goodness_of_fit
  ACGTAAATCCCCACAA A230212d28_rd512: goodness_of_fit
  AGATGGAGGAATAAAC A230212d28_rd512: goodness_of_fit
  AGCAGACACTTTACAT A230212d28_rd512: goodness_of_fit
  AGCTATGCCTAGTGAA A230212d28_rd512: goodness_of_fit
  AGGGACTTTATTGTCC A230212d28_rd512: goodness_of_fit
  AGTTATGTAAAACGTG A230212d28_rd512: goodness_of_fit
  ATAAAGAATCCCTTGA A230212d28_rd512: goodness_of_fit
  ATAATAATCATCAAGA A230212d28_rd512: goodness_of_fit
  ATGGTTATCTTACCTT A230212d28_rd512: goodness_of_fit
  ATTCAATACGTACTTA A230212d28_rd512: goodness_of_fit
  CAAGAAATGTAGTGAA A230212d28_rd512: goodness_of_fit
  CAATGGATAATGATAG A230212d28_rd512: goodness_of_fit
  CACCACAGTTACTTAA A230212d28_rd512: goodness_of_fit
  CACCTTCATCCTAAAG A230212d28_rd512: goodness_of_fit
  CAGTAGCAAAACATGC A230212d28_rd512: goodness_of_fit
  CATAATGCACAAACGC A230212d28_rd512: goodness_of_fit
  CATATTCTAAAATTGA A230212d28_rd512
: goodness_of_fit
  CATCATTATTACAAAG A230212d28_rd512: goodness_of_fit
  CCAATCATGTATCACA A230212d28_rd512: goodness_of_fit
  CCACAAGTTTGAAAAC A230212d28_rd512: goodness_of_fit
  CCACGTTCATTAGATG A230212d28_rd512: goodness_of_fit
  CCAGAGACACGCTAGG A230212d28_rd512: goodness_of_fit
  CCATATATAAGAAACC A230212d28_rd512: goodness_of_fit
  CCATCACCTTATACAC A230212d28_rd512: goodness_of_fit
  CCCATATACTCACAGA A230212d28_rd512: goodness_of_fit
  CCCCAGGTATAAAATA A230212d28_rd512: goodness_of_fit
  CGATCTTTACGAAAAA A230212d28_rd512: goodness_of_fit
  CGCAAGGGATACTAAC A230212d28_rd512: goodness_of_fit
  CGCCGAACGGCGGCGC A230212d28_rd512: goodness_of_fit
  CGCGAATCACTAAGTA A230212d28_rd512: goodness_of_fit
  CTGTGAAAAAAAATAC A230212d28_rd512: goodness_of_fit
  GAAAGAAAGCTATATG A230212d28_rd512: goodness_of_fit
  GAAGTAACAAACTATG A230212d28_rd512: goodness_of_fit
  GACATCAAATAGCAAC A230212d28_rd512: goodness_of_fit
  GACCTCCTGGGCACGC A230212d28_rd512: goodness_of_fit
  GAGATAGCCCAGAGGT A230212d28_rd512: goodness_of_fit
  GAGCCCGAATAGCAAG A230212d28_rd512: goodness_of_fit
  GATCTGCTTGGAATGT A230212d28_rd512: goodness_of_fit
  GCAACGAGGTGTAACC A230212d28_rd512: goodness_of_fit
  GCCCATTGAACGCAGC A230212d28_rd512: goodness_of_fit
  GGCAATAAGTTAAATG A230212d28_rd512: goodness_of_fit
  GTTATTATGACTTCAT A230212d28_rd512: goodness_of_fit
  TAAACTGTAACTTACA A230212d28_rd512: goodness_of_fit
  TACCAATGTCATTTGA A230212d28_rd512: goodness_of_fit
  TACGAAAATCAAGAGC A230212d28_rd512: goodness_of_fit
  TACGACGGAAACAGAA A230212d28_rd512: goodness_of_fit
  TAGATAATAAGATTCA A230212d28_rd512: goodness_of_fit
  TAGCTGGGCAAAGGCT A230212d28_rd512: goodness_of_fit
  TATCATTTCATCTACA A230212d28_rd512: goodness_of_fit
  TATCGCAATATGATAA A230212d28_rd512: goodness_of_fit
  TATTATCTAAACGGCG A230212d28_rd512: goodness_of_fit
  TCAACCCTTCGATGTA A230212d28_rd512: goodness_of_fit
  TCCAAACAGCGTTAAA A230212d28_rd512: goodness_of_fit
  TCGCGGTAGATTTGCG A230212d28_rd512: goodness_of_fit
  TGAATTGCGTGATGGG A230212d28_rd512: goodness_of_fit
  TGATCCGCAAGCTTAG A230212d28_rd512: goodness_of_fit
  TGATTCGTCAATTCAT A230212d28_rd512: goodness_of_fit
  TGTAGTATAAGAATAA A230212d28_rd512: goodness_of_fit
  TTACGTCAATGTTTGA A230212d28_rd512: goodness_of_fit
  TTAGCAGTTAACGTAT A230212d28_rd512: goodness_of_fit
  TTAGTCATCTGGGTGC A230212d28_rd512: goodness_of_fit
  TTATAATGGCCGGTAT A230212d28_rd512: goodness_of_fit
  TTGCAATTGAAACATA A230212d28_rd512: goodness_of_fit
  TTTATGCCGATAGAGA A230212d28_rd512: goodness_of_fit
serum_replicates: {}